Index: src/Common/SharpMap/Layers/WmsLayer.cs =================================================================== diff -u -r8f6ae890fed8e8eae3a32f9c0498a10f82e0ddf9 -r5fc71a385897af92ccb092f2f969b5709afab85a --- src/Common/SharpMap/Layers/WmsLayer.cs (.../WmsLayer.cs) (revision 8f6ae890fed8e8eae3a32f9c0498a10f82e0ddf9) +++ src/Common/SharpMap/Layers/WmsLayer.cs (.../WmsLayer.cs) (revision 5fc71a385897af92ccb092f2f969b5709afab85a) @@ -18,150 +18,141 @@ using System; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.Diagnostics; using System.Drawing; using System.Drawing.Imaging; +using System.IO; +using System.Net; using System.Text; +using System.Web; +using System.Web.Caching; using GeoAPI.Geometries; using SharpMap.Api; +using SharpMap.Rendering.Exceptions; +using SharpMap.Web.Wms; namespace SharpMap.Layers { - /// - /// Web Map Service layer - /// - /// - /// The WmsLayer is currently very basic and doesn't support automatic fetching of the WMS Service Description. - /// Instead you would have to add the nessesary parameters to the URL, - /// and the WmsLayer will set the remaining BoundingBox property and proper requests that changes between the requests. - /// See the example below. - /// - /// - /// The following example creates a map with a WMS layer the Demis WMS Server - /// - /// myMap = new SharpMap.Map(new System.Drawing.Size(500,250); - /// string wmsUrl = "http://www2.demis.nl/mapserver/request.asp"; - /// SharpMap.Layers.WmsLayer myLayer = new SharpMap.Layers.WmsLayer("Demis WMS", myLayer); - /// myLayer.AddLayer("Bathymetry"); - /// myLayer.AddLayer("Countries"); - /// myLayer.AddLayer("Topography"); - /// myLayer.AddLayer("Hillshading"); - /// myLayer.SetImageFormat(layWms.OutputFormats[0]); - /// myLayer.SpatialReferenceSystem = "EPSG:4326"; + /// + /// Web Map Service layer + /// + /// + /// The WmsLayer is currently very basic and doesn't support automatic fetching of the WMS Service Description. + /// Instead you would have to add the nessesary parameters to the URL, + /// and the WmsLayer will set the remaining BoundingBox property and proper requests that changes between the requests. + /// See the example below. + /// + /// + /// The following example creates a map with a WMS layer the Demis WMS Server + /// + /// myMap = new SharpMap.Map(new System.Drawing.Size(500,250); + /// string wmsUrl = "http://www2.demis.nl/mapserver/request.asp"; + /// SharpMap.Layers.WmsLayer myLayer = new SharpMap.Layers.WmsLayer("Demis WMS", myLayer); + /// myLayer.AddLayer("Bathymetry"); + /// myLayer.AddLayer("Countries"); + /// myLayer.AddLayer("Topography"); + /// myLayer.AddLayer("Hillshading"); + /// myLayer.SetImageFormat(layWms.OutputFormats[0]); + /// myLayer.SpatialReferenceSystem = "EPSG:4326"; /// myMap.Layers.Add(myLayer); - /// myMap.Center = new SharpMap.Geometries.Point(0, 0); - /// myMap.Zoom = 360; - /// myMap.MaximumZoom = 360; - /// myMap.MinimumZoom = 0.1; - /// - /// - public class WmsLayer : SharpMap.Layers.Layer - { - private SharpMap.Web.Wms.Client wmsClient; - private string mimeType = ""; - - /// - /// Initializes a new layer, and downloads and parses the service description - /// - /// In and ASP.NET application the service description is automatically cached for 24 hours when not specified + /// myMap.Center = new SharpMap.Geometries.Point(0, 0); + /// myMap.Zoom = 360; + /// myMap.MaximumZoom = 360; + /// myMap.MinimumZoom = 0.1; + /// + /// + public class WmsLayer : Layer + { + private Client wmsClient; + private string mimeType = ""; + + private TimeSpan cachetime; + + private string url; + + private IList layerList; + + private Collection stylesList; + + private string spatialReferenceSystem; + + private ImageAttributes imageAttributes; + + private ICredentials credentials; + + private WebProxy proxy; + + private int timeOut; + + /// + /// Initializes a new layer, and downloads and parses the service description + /// + /// In and ASP.NET application the service description is automatically cached for 24 hours when not specified public WmsLayer() - : this("", "", new TimeSpan(24, 0, 0)) - { - } - /// - /// Initializes a new layer, and downloads and parses the service description - /// - /// In and ASP.NET application the service description is automatically cached for 24 hours when not specified - /// Layername - /// Url of WMS server - public WmsLayer(string layername, string url) - : this(layername, url, new TimeSpan(24, 0, 0)) - { - } - /// - /// Initializes a new layer, and downloads and parses the service description - /// - /// Layername - /// Url of WMS server - /// Time for caching Service Description (ASP.NET only) - public WmsLayer(string layername, string url, TimeSpan cachetime) - : this(layername, url, cachetime, null) - { - } - /// - /// Initializes a new layer, and downloads and parses the service description - /// - /// In and ASP.NET application the service description is automatically cached for 24 hours when not specified - /// Layername - /// Url of WMS server - /// Proxy - public WmsLayer(string layername, string url, System.Net.WebProxy proxy) - : this(layername, url, new TimeSpan(24,0,0), proxy) - { - } - /// - /// Initializes a new layer, and downloads and parses the service description - /// - /// Layername - /// Url of WMS server - /// Time for caching Service Description (ASP.NET only) - /// Proxy - public WmsLayer(string layername, string url, TimeSpan cachetime, System.Net.WebProxy proxy) - { - this.proxy = proxy; - timeOut = 10000; - this.Name = layername; - this.Cachetime = cachetime; - this.Url = url; // Also does the initialization if an non-empty url was given - } + : this("", "", new TimeSpan(24, 0, 0)) {} - private void Initialize() + /// + /// Initializes a new layer, and downloads and parses the service description + /// + /// In and ASP.NET application the service description is automatically cached for 24 hours when not specified + /// Layername + /// Url of WMS server + public WmsLayer(string layername, string url) + : this(layername, url, new TimeSpan(24, 0, 0)) {} + + /// + /// Initializes a new layer, and downloads and parses the service description + /// + /// Layername + /// Url of WMS server + /// Time for caching Service Description (ASP.NET only) + public WmsLayer(string layername, string url, TimeSpan cachetime) + : this(layername, url, cachetime, null) {} + + /// + /// Initializes a new layer, and downloads and parses the service description + /// + /// In and ASP.NET application the service description is automatically cached for 24 hours when not specified + /// Layername + /// Url of WMS server + /// Proxy + public WmsLayer(string layername, string url, WebProxy proxy) + : this(layername, url, new TimeSpan(24, 0, 0), proxy) {} + + /// + /// Initializes a new layer, and downloads and parses the service description + /// + /// Layername + /// Url of WMS server + /// Time for caching Service Description (ASP.NET only) + /// Proxy + public WmsLayer(string layername, string url, TimeSpan cachetime, WebProxy proxy) { - continueOnError = true; - if (System.Web.HttpContext.Current != null && System.Web.HttpContext.Current.Cache["SharpMap_WmsClient_" + url] != null) + this.proxy = proxy; + timeOut = 10000; + Name = layername; + Cachetime = cachetime; + Url = url; // Also does the initialization if an non-empty url was given + } + + public virtual TimeSpan Cachetime + { + get { - wmsClient = (SharpMap.Web.Wms.Client)System.Web.HttpContext.Current.Cache["SharpMap_WmsClient_" + url]; + return cachetime; } - else + set { - wmsClient = new SharpMap.Web.Wms.Client(url, proxy); - if (System.Web.HttpContext.Current != null) - System.Web.HttpContext.Current.Cache.Insert("SharpMap_WmsClient_" + url, wmsClient, null, - System.Web.Caching.Cache.NoAbsoluteExpiration, cachetime); + cachetime = value; } - //Set default mimetype - We prefer compressed formats - if (OutputFormats.Contains("image/jpeg")) mimeType = "image/jpeg"; - else if (OutputFormats.Contains("image/png")) mimeType = "image/png"; - else if (OutputFormats.Contains("image/gif")) mimeType = "image/gif"; - else //None of the default formats supported - Look for the first supported output format - { - bool formatSupported = false; - foreach (System.Drawing.Imaging.ImageCodecInfo encoder in System.Drawing.Imaging.ImageCodecInfo.GetImageEncoders()) - if (OutputFormats.Contains(encoder.MimeType.ToLower())) - { - formatSupported = true; - mimeType = encoder.MimeType; - break; - } - if (!formatSupported) - throw new ArgumentException("GDI+ doesn't not support any of the mimetypes supported by this WMS service"); - } - layerList = new Collection(); - stylesList = new Collection(); } - private TimeSpan cachetime; - - public virtual TimeSpan Cachetime - { - get { return cachetime; } - set { cachetime = value; } - } - - private string url; - public virtual string Url - { - get { return url; } + { + get + { + return url; + } set { url = value; @@ -170,439 +161,608 @@ Initialize(); } } - } + } - public virtual string MimeType - { - get { return mimeType; } - set { mimeType = value; } - } + public virtual string MimeType + { + get + { + return mimeType; + } + set + { + mimeType = value; + } + } - private IList layerList; - - /// - /// Gets the list of enabled layers - /// + /// + /// Gets the list of enabled layers + /// public virtual IList LayerList - { - get { return layerList; } - set { layerList = value; } - } + { + get + { + return layerList; + } + set + { + layerList = value; + } + } - /// - /// Adds a layer to WMS request - /// - /// Layer names are case sensitive. - /// Name of layer - /// Throws an exception is an unknown layer is added - public virtual void AddLayer(string name) - { - if(!LayerExists(wmsClient.Layer,name)) - throw new ArgumentException("Cannot add WMS Layer - Unknown layername"); - - layerList.Add(name); - } - /// - /// Recursive method for checking whether a layername exists - /// - /// - /// - /// - private bool LayerExists(SharpMap.Web.Wms.Client.WmsServerLayer layer, string name) - { - if(name == layer.Name) return true; - foreach (SharpMap.Web.Wms.Client.WmsServerLayer childlayer in layer.ChildLayers) - if (LayerExists(childlayer,name)) return true; - return false; - } - /// - /// Removes a layer from the layer list - /// - /// Name of layer to remove - public virtual void RemoveLayer(string name) - { - layerList.Remove(name); - } - /// - /// Removes the layer at the specified index - /// - /// - public virtual void RemoveLayerAt(int index) - { - layerList.RemoveAt(index); - } - /// - /// Removes all layers - /// - public virtual void RemoveAllLayers() - { - layerList.Clear(); - } - - private Collection stylesList; - - /// - /// Gets the list of enabled styles - /// + /// + /// Gets the list of enabled styles + /// public virtual Collection StylesList - { - get { return stylesList; } - } + { + get + { + return stylesList; + } + } - /// - /// Adds a style to the style collection - /// - /// Name of style - /// Throws an exception is an unknown layer is added - public virtual void AddStyle(string name) - { - if (!StyleExists(wmsClient.Layer, name)) - throw new ArgumentException("Cannot add WMS Layer - Unknown layername"); - stylesList.Add(name); - } + /// + /// Gets the hiarchial list of available WMS layers from this service + /// + public virtual Client.WmsServerLayer RootLayer + { + get + { + return wmsClient.Layer; + } + } - /// - /// Recursive method for checking whether a layername exists - /// - /// layer - /// name of style - /// True of style exists - private bool StyleExists(SharpMap.Web.Wms.Client.WmsServerLayer layer, string name) - { - foreach(SharpMap.Web.Wms.Client.WmsLayerStyle style in layer.Style) - if (name == style.Name) return true; - foreach (SharpMap.Web.Wms.Client.WmsServerLayer childlayer in layer.ChildLayers) - if (StyleExists(childlayer, name)) return true; - return false; - } - /// - /// Removes a style from the collection - /// - /// Name of style - public virtual void RemoveStyle(string name) - { - stylesList.Remove(name); - } - /// - /// Removes a style at specified index - /// - /// Index - public virtual void RemoveStyleAt(int index) - { - stylesList.RemoveAt(index); - } - /// - /// Removes all styles from the list - /// - public virtual void RemoveAllStyles() - { - stylesList.Clear(); - } - - /// - /// Sets the image type to use when requesting images from the WMS server - /// - /// - /// See the property for a list of available mime types supported by the WMS server - /// - /// Throws an exception if either the mime type isn't offered by the WMS - /// or GDI+ doesn't support this mime type. - /// Mime type of image format - public virtual void SetImageFormat(string mimeType) - { - if (!OutputFormats.Contains(mimeType)) - throw new ArgumentException("WMS service doesn't not offer mimetype '" + mimeType + "'"); - //Check whether SharpMap supports the specified mimetype - bool formatSupported = false; - foreach (System.Drawing.Imaging.ImageCodecInfo encoder in System.Drawing.Imaging.ImageCodecInfo.GetImageEncoders()) - if (encoder.MimeType.ToLower() == mimeType.ToLower()) - { - formatSupported = true; - break; - } - if (!formatSupported) - throw new ArgumentException("GDI+ doesn't not support mimetype '" + mimeType + "'"); - this.mimeType = mimeType; - } - - /// - /// Gets the hiarchial list of available WMS layers from this service - /// - public virtual SharpMap.Web.Wms.Client.WmsServerLayer RootLayer - { - get { return wmsClient.Layer; } - } - /// - /// Gets the list of available formats - /// + /// + /// Gets the list of available formats + /// public virtual Collection OutputFormats - { - get { return wmsClient.GetMapOutputFormats; } - } + { + get + { + return wmsClient.GetMapOutputFormats; + } + } - private string spatialReferenceSystem; - - /// - /// Gets or sets the spatial reference used for the WMS server request - /// + /// + /// Gets or sets the spatial reference used for the WMS server request + /// public virtual string SpatialReferenceSystem - { - get { return spatialReferenceSystem; } - set { spatialReferenceSystem = value; } - } - + { + get + { + return spatialReferenceSystem; + } + set + { + spatialReferenceSystem = value; + } + } - /// - /// Gets the service description from this server - /// - public virtual SharpMap.Web.Wms.Capabilities.WmsServiceDescription ServiceDescription - { - get { return wmsClient.ServiceDescription; } - } - /// - /// Gets the WMS Server version of this service - /// + /// + /// Gets the service description from this server + /// + public virtual Capabilities.WmsServiceDescription ServiceDescription + { + get + { + return wmsClient.ServiceDescription; + } + } + + /// + /// Gets the WMS Server version of this service + /// public virtual string Version - { - get { return wmsClient.WmsVersion; } - } + { + get + { + return wmsClient.WmsVersion; + } + } - private ImageAttributes imageAttributes; - - /// - /// When specified, applies image attributes at image (fx. make WMS layer semi-transparent) - /// - /// - /// You can make the WMS layer semi-transparent by settings a up a ColorMatrix, - /// or scale/translate the colors in any other way you like. - /// - /// Setting the WMS layer to be semi-transparent. - /// - /// float[][] colorMatrixElements = { - /// new float[] {1, 0, 0, 0, 0}, - /// new float[] {0, 1, 0, 0, 0}, - /// new float[] {0, 0, 1, 0, 0}, - /// new float[] {0, 0, 0, 0.5, 0}, - /// new float[] {0, 0, 0, 0, 1}}; - /// ColorMatrix colorMatrix = new ColorMatrix(colorMatrixElements); - /// ImageAttributes imageAttributes = new ImageAttributes(); - /// imageAttributes.SetColorMatrix( - /// colorMatrix, - /// ColorMatrixFlag.Default, - /// ColorAdjustType.Bitmap); - /// myWmsLayer.ImageAttributes = imageAttributes; - /// - /// - /// + /// + /// When specified, applies image attributes at image (fx. make WMS layer semi-transparent) + /// + /// + /// You can make the WMS layer semi-transparent by settings a up a ColorMatrix, + /// or scale/translate the colors in any other way you like. + /// + /// Setting the WMS layer to be semi-transparent. + /// + /// float[][] colorMatrixElements = { + /// new float[] {1, 0, 0, 0, 0}, + /// new float[] {0, 1, 0, 0, 0}, + /// new float[] {0, 0, 1, 0, 0}, + /// new float[] {0, 0, 0, 0.5, 0}, + /// new float[] {0, 0, 0, 0, 1}}; + /// ColorMatrix colorMatrix = new ColorMatrix(colorMatrixElements); + /// ImageAttributes imageAttributes = new ImageAttributes(); + /// imageAttributes.SetColorMatrix( + /// colorMatrix, + /// ColorMatrixFlag.Default, + /// ColorAdjustType.Bitmap); + /// myWmsLayer.ImageAttributes = imageAttributes; + /// + /// + /// public virtual ImageAttributes ImageAttributes - { - get { return imageAttributes; } - set { imageAttributes = value; } - } - + { + get + { + return imageAttributes; + } + set + { + imageAttributes = value; + } + } - #region ILayer Members + /// + /// Provides the base authentication interface for retrieving credentials for Web client authentication. + /// + public virtual ICredentials Credentials + { + get + { + return credentials; + } + set + { + credentials = value; + } + } - /// - /// Renders the layer - /// - /// Graphics object reference - /// Map which is rendered - public override void OnRender(System.Drawing.Graphics g, IMap map) - { - SharpMap.Web.Wms.Client.WmsOnlineResource resource = GetPreferredMethod(); - Uri myUri = new Uri(GetRequestUrl(map.Envelope, map.Size)); - System.Net.WebRequest myWebRequest = System.Net.WebRequest.Create(myUri); - myWebRequest.Method = resource.Type; - myWebRequest.Timeout = timeOut; - if (credentials != null) - myWebRequest.Credentials = credentials; - else - myWebRequest.Credentials = System.Net.CredentialCache.DefaultCredentials; + /// + /// Gets or sets the proxy used for requesting a webresource + /// + public virtual WebProxy Proxy + { + get + { + return proxy; + } + set + { + proxy = value; + } + } - if (proxy != null) - myWebRequest.Proxy = proxy; + /// + /// Timeout of webrequest in milliseconds. Defaults to 10 seconds + /// + public virtual int TimeOut + { + get + { + return timeOut; + } + set + { + timeOut = value; + } + } - try - { - System.Net.HttpWebResponse myWebResponse = (System.Net.HttpWebResponse)myWebRequest.GetResponse(); - System.IO.Stream dataStream = myWebResponse.GetResponseStream(); + public virtual string LayerTitle + { + get + { + return RootLayer.Name; + } + } - if (myWebResponse.ContentType.StartsWith("image")) - { - System.Drawing.Image img = System.Drawing.Image.FromStream(myWebResponse.GetResponseStream()); - if (imageAttributes != null) - g.DrawImage(img, new Rectangle(0, 0, img.Width, img.Height), 0, 0, - img.Width, img.Height, GraphicsUnit.Pixel, this.ImageAttributes); - else - g.DrawImageUnscaled(img, 0, 0,map.Size.Width,map.Size.Height); - } - dataStream.Close(); - myWebResponse.Close(); - } - catch (System.Net.WebException webEx) - { - if (!continueOnError) - throw (new SharpMap.Rendering.Exceptions.RenderException("There was a problem connecting to the WMS server when rendering layer '" + this.Name + "'", webEx)); - else - //Write out a trace warning instead of throwing an error to help debugging WMS problems - System.Diagnostics.Trace.Write("There was a problem connecting to the WMS server when rendering layer '" + this.Name + "': " + webEx.Message); - } - catch (System.Exception ex) - { - if (!continueOnError) - throw (new SharpMap.Rendering.Exceptions.RenderException("There was a problem rendering layer '" + this.Name + "'", ex)); - else - //Write out a trace warning instead of throwing an error to help debugging WMS problems - System.Diagnostics.Trace.Write("There was a problem connecting to the WMS server when rendering layer '" + this.Name + "': " + ex.Message); - } - } + /// + /// Adds a layer to WMS request + /// + /// Layer names are case sensitive. + /// Name of layer + /// Throws an exception is an unknown layer is added + public virtual void AddLayer(string name) + { + if (!LayerExists(wmsClient.Layer, name)) + { + throw new ArgumentException("Cannot add WMS Layer - Unknown layername"); + } - /// - /// Gets the URL for a map request base on current settings, the image size and boundingbox - /// - /// Area the WMS request should cover - /// Size of image - /// URL for WMS request - public virtual string GetRequestUrl(IEnvelope box, System.Drawing.Size size) - { - SharpMap.Web.Wms.Client.WmsOnlineResource resource = GetPreferredMethod(); - System.Text.StringBuilder strReq = new StringBuilder(resource.OnlineResource); - if(!resource.OnlineResource.Contains("?")) - strReq.Append("?"); - if (!strReq.ToString().EndsWith("&") && !strReq.ToString().EndsWith("?")) - strReq.Append("&"); + layerList.Add(name); + } - strReq.AppendFormat(SharpMap.Map.numberFormat_EnUS, "REQUEST=GetMap&BBOX={0},{1},{2},{3}", - box.MinX, box.MinY, box.MaxX, box.MaxY); - strReq.AppendFormat("&WIDTH={0}&Height={1}", size.Width, size.Height); - strReq.Append("&Layers="); - if (layerList != null && layerList.Count > 0) - { - foreach (string layer in layerList) - strReq.AppendFormat("{0},", layer); - strReq.Remove(strReq.Length - 1, 1); - } - strReq.AppendFormat("&FORMAT={0}", mimeType); - if (spatialReferenceSystem == string.Empty) - throw new ApplicationException("Spatial reference system not set"); - if(wmsClient.WmsVersion=="1.3.0") - strReq.AppendFormat("&CRS={0}", spatialReferenceSystem); - else - strReq.AppendFormat("&SRS={0}", spatialReferenceSystem); - strReq.AppendFormat("&VERSION={0}", wmsClient.WmsVersion); - strReq.Append("&Styles="); - if (stylesList != null && stylesList.Count > 0) - { - foreach (string style in stylesList) - strReq.AppendFormat("{0},", style); - strReq.Remove(strReq.Length - 1, 1); - } - return strReq.ToString(); - } + /// + /// Removes a layer from the layer list + /// + /// Name of layer to remove + public virtual void RemoveLayer(string name) + { + layerList.Remove(name); + } - /// - /// Returns the extent of the layer - /// - /// Bounding box corresponding to the extent of the features in the layer - public override IEnvelope Envelope - { - get - { - return RootLayer.LatLonBoundingBox; - } - } + /// + /// Removes the layer at the specified index + /// + /// + public virtual void RemoveLayerAt(int index) + { + layerList.RemoveAt(index); + } - private Boolean continueOnError; + /// + /// Removes all layers + /// + public virtual void RemoveAllLayers() + { + layerList.Clear(); + } - /// - /// Specifies whether to throw an exception if the Wms request failed, or to just skip rendering the layer - /// - public virtual Boolean ContinueOnError - { - get { return continueOnError; } - set { continueOnError = value; } - } + /// + /// Adds a style to the style collection + /// + /// Name of style + /// Throws an exception is an unknown layer is added + public virtual void AddStyle(string name) + { + if (!StyleExists(wmsClient.Layer, name)) + { + throw new ArgumentException("Cannot add WMS Layer - Unknown layername"); + } + stylesList.Add(name); + } - /// - /// Returns the type of the layer - /// - //public override SharpMap.Layers.Layertype LayerType - //{ - // get { return SharpMap.Layers.Layertype.Wms; } - //} + /// + /// Removes a style from the collection + /// + /// Name of style + public virtual void RemoveStyle(string name) + { + stylesList.Remove(name); + } - #endregion + /// + /// Removes a style at specified index + /// + /// Index + public virtual void RemoveStyleAt(int index) + { + stylesList.RemoveAt(index); + } - private SharpMap.Web.Wms.Client.WmsOnlineResource GetPreferredMethod() - { - //We prefer posting. Seek for supported post method - for (int i = 0; i < wmsClient.GetMapRequests.Length; i++) - if (wmsClient.GetMapRequests[i].Type.ToLower() == "post") - { - return wmsClient.GetMapRequests[i]; - } - //Next we prefer the 'get' method - for (int i = 0; i < wmsClient.GetMapRequests.Length; i++) + /// + /// Removes all styles from the list + /// + public virtual void RemoveAllStyles() + { + stylesList.Clear(); + } + + /// + /// Sets the image type to use when requesting images from the WMS server + /// + /// + /// See the property for a list of available mime types supported by the WMS server + /// + /// Throws an exception if either the mime type isn't offered by the WMS + /// or GDI+ doesn't support this mime type. + /// Mime type of image format + public virtual void SetImageFormat(string mimeType) + { + if (!OutputFormats.Contains(mimeType)) { - if (wmsClient.GetMapRequests[i].Type.ToLower() == "get") + throw new ArgumentException("WMS service doesn't not offer mimetype '" + mimeType + "'"); + } + //Check whether SharpMap supports the specified mimetype + bool formatSupported = false; + foreach (ImageCodecInfo encoder in ImageCodecInfo.GetImageEncoders()) + { + if (encoder.MimeType.ToLower() == mimeType.ToLower()) { - return wmsClient.GetMapRequests[i]; + formatSupported = true; + break; } } - return wmsClient.GetMapRequests[0]; - } + if (!formatSupported) + { + throw new ArgumentException("GDI+ doesn't not support mimetype '" + mimeType + "'"); + } + this.mimeType = mimeType; + } - private System.Net.ICredentials credentials; + #region ICloneable Members - /// - /// Provides the base authentication interface for retrieving credentials for Web client authentication. - /// - public virtual System.Net.ICredentials Credentials - { - get { return credentials; } - set { credentials = value; } - } + /// + /// Clones the object + /// + /// + public override object Clone() + { + return new WmsLayer(Name, Url); + } - private System.Net.WebProxy proxy; + #endregion - /// - /// Gets or sets the proxy used for requesting a webresource - /// - public virtual System.Net.WebProxy Proxy - { - get { return proxy; } - set { proxy = value; } - } - + private void Initialize() + { + continueOnError = true; + if (HttpContext.Current != null && HttpContext.Current.Cache["SharpMap_WmsClient_" + url] != null) + { + wmsClient = (Client) HttpContext.Current.Cache["SharpMap_WmsClient_" + url]; + } + else + { + wmsClient = new Client(url, proxy); + if (HttpContext.Current != null) + { + HttpContext.Current.Cache.Insert("SharpMap_WmsClient_" + url, wmsClient, null, + Cache.NoAbsoluteExpiration, cachetime); + } + } + //Set default mimetype - We prefer compressed formats + if (OutputFormats.Contains("image/jpeg")) + { + mimeType = "image/jpeg"; + } + else if (OutputFormats.Contains("image/png")) + { + mimeType = "image/png"; + } + else if (OutputFormats.Contains("image/gif")) + { + mimeType = "image/gif"; + } + else //None of the default formats supported - Look for the first supported output format + { + bool formatSupported = false; + foreach (ImageCodecInfo encoder in ImageCodecInfo.GetImageEncoders()) + { + if (OutputFormats.Contains(encoder.MimeType.ToLower())) + { + formatSupported = true; + mimeType = encoder.MimeType; + break; + } + } + if (!formatSupported) + { + throw new ArgumentException("GDI+ doesn't not support any of the mimetypes supported by this WMS service"); + } + } + layerList = new Collection(); + stylesList = new Collection(); + } - private int timeOut; + /// + /// Recursive method for checking whether a layername exists + /// + /// + /// + /// + private bool LayerExists(Client.WmsServerLayer layer, string name) + { + if (name == layer.Name) + { + return true; + } + foreach (Client.WmsServerLayer childlayer in layer.ChildLayers) + { + if (LayerExists(childlayer, name)) + { + return true; + } + } + return false; + } - /// - /// Timeout of webrequest in milliseconds. Defaults to 10 seconds - /// - public virtual int TimeOut - { - get { return timeOut; } - set { timeOut = value; } - } + /// + /// Recursive method for checking whether a layername exists + /// + /// layer + /// name of style + /// True of style exists + private bool StyleExists(Client.WmsServerLayer layer, string name) + { + foreach (Client.WmsLayerStyle style in layer.Style) + { + if (name == style.Name) + { + return true; + } + } + foreach (Client.WmsServerLayer childlayer in layer.ChildLayers) + { + if (StyleExists(childlayer, name)) + { + return true; + } + } + return false; + } - #region ICloneable Members + #region ILayer Members - /// - /// Clones the object - /// - /// - public override object Clone() - { - return new WmsLayer(Name, Url); - } + /// + /// Renders the layer + /// + /// Graphics object reference + /// Map which is rendered + public override void OnRender(Graphics g, IMap map) + { + Client.WmsOnlineResource resource = GetPreferredMethod(); + Uri myUri = new Uri(GetRequestUrl(map.Envelope, map.Size)); + WebRequest myWebRequest = WebRequest.Create(myUri); + myWebRequest.Method = resource.Type; + myWebRequest.Timeout = timeOut; + if (credentials != null) + { + myWebRequest.Credentials = credentials; + } + else + { + myWebRequest.Credentials = CredentialCache.DefaultCredentials; + } - #endregion + if (proxy != null) + { + myWebRequest.Proxy = proxy; + } - public virtual string LayerTitle - { - get { return RootLayer.Name; } - } - } -} + try + { + HttpWebResponse myWebResponse = (HttpWebResponse) myWebRequest.GetResponse(); + Stream dataStream = myWebResponse.GetResponseStream(); + + if (myWebResponse.ContentType.StartsWith("image")) + { + Image img = Image.FromStream(myWebResponse.GetResponseStream()); + if (imageAttributes != null) + { + g.DrawImage(img, new Rectangle(0, 0, img.Width, img.Height), 0, 0, + img.Width, img.Height, GraphicsUnit.Pixel, ImageAttributes); + } + else + { + g.DrawImageUnscaled(img, 0, 0, map.Size.Width, map.Size.Height); + } + } + dataStream.Close(); + myWebResponse.Close(); + } + catch (WebException webEx) + { + if (!continueOnError) + { + throw (new RenderException("There was a problem connecting to the WMS server when rendering layer '" + Name + "'", webEx)); + } + else + { + //Write out a trace warning instead of throwing an error to help debugging WMS problems + Trace.Write("There was a problem connecting to the WMS server when rendering layer '" + Name + "': " + webEx.Message); + } + } + catch (Exception ex) + { + if (!continueOnError) + { + throw (new RenderException("There was a problem rendering layer '" + Name + "'", ex)); + } + else + { + //Write out a trace warning instead of throwing an error to help debugging WMS problems + Trace.Write("There was a problem connecting to the WMS server when rendering layer '" + Name + "': " + ex.Message); + } + } + } + + /// + /// Gets the URL for a map request base on current settings, the image size and boundingbox + /// + /// Area the WMS request should cover + /// Size of image + /// URL for WMS request + public virtual string GetRequestUrl(IEnvelope box, Size size) + { + Client.WmsOnlineResource resource = GetPreferredMethod(); + StringBuilder strReq = new StringBuilder(resource.OnlineResource); + if (!resource.OnlineResource.Contains("?")) + { + strReq.Append("?"); + } + if (!strReq.ToString().EndsWith("&") && !strReq.ToString().EndsWith("?")) + { + strReq.Append("&"); + } + + strReq.AppendFormat(SharpMap.Map.numberFormat_EnUS, "REQUEST=GetMap&BBOX={0},{1},{2},{3}", + box.MinX, box.MinY, box.MaxX, box.MaxY); + strReq.AppendFormat("&WIDTH={0}&Height={1}", size.Width, size.Height); + strReq.Append("&Layers="); + if (layerList != null && layerList.Count > 0) + { + foreach (string layer in layerList) + { + strReq.AppendFormat("{0},", layer); + } + strReq.Remove(strReq.Length - 1, 1); + } + strReq.AppendFormat("&FORMAT={0}", mimeType); + if (spatialReferenceSystem == string.Empty) + { + throw new ApplicationException("Spatial reference system not set"); + } + if (wmsClient.WmsVersion == "1.3.0") + { + strReq.AppendFormat("&CRS={0}", spatialReferenceSystem); + } + else + { + strReq.AppendFormat("&SRS={0}", spatialReferenceSystem); + } + strReq.AppendFormat("&VERSION={0}", wmsClient.WmsVersion); + strReq.Append("&Styles="); + if (stylesList != null && stylesList.Count > 0) + { + foreach (string style in stylesList) + { + strReq.AppendFormat("{0},", style); + } + strReq.Remove(strReq.Length - 1, 1); + } + return strReq.ToString(); + } + + /// + /// Returns the extent of the layer + /// + /// Bounding box corresponding to the extent of the features in the layer + public override IEnvelope Envelope + { + get + { + return RootLayer.LatLonBoundingBox; + } + } + + private Boolean continueOnError; + + /// + /// Specifies whether to throw an exception if the Wms request failed, or to just skip rendering the layer + /// + public virtual Boolean ContinueOnError + { + get + { + return continueOnError; + } + set + { + continueOnError = value; + } + } + + /// + /// Returns the type of the layer + /// + //public override SharpMap.Layers.Layertype LayerType + //{ + // get { return SharpMap.Layers.Layertype.Wms; } + //} + + #endregion + private Client.WmsOnlineResource GetPreferredMethod() + { + //We prefer posting. Seek for supported post method + for (int i = 0; i < wmsClient.GetMapRequests.Length; i++) + { + if (wmsClient.GetMapRequests[i].Type.ToLower() == "post") + { + return wmsClient.GetMapRequests[i]; + } + } + //Next we prefer the 'get' method + for (int i = 0; i < wmsClient.GetMapRequests.Length; i++) + { + if (wmsClient.GetMapRequests[i].Type.ToLower() == "get") + { + return wmsClient.GetMapRequests[i]; + } + } + return wmsClient.GetMapRequests[0]; + } + } +} \ No newline at end of file