WmsServer.cs
上传用户:sex100000
上传日期:2013-11-09
资源大小:1377k
文件大小:13k
源码类别:

GIS编程

开发平台:

C#

  1. // Copyright 2005, 2006 - Morten Nielsen (www.iter.dk)
  2. //
  3. // This file is part of SharpMap.
  4. // SharpMap is free software; you can redistribute it and/or modify
  5. // it under the terms of the GNU Lesser General Public License as published by
  6. // the Free Software Foundation; either version 2 of the License, or
  7. // (at your option) any later version.
  8. // 
  9. // SharpMap is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12. // GNU Lesser General Public License for more details.
  13. // You should have received a copy of the GNU Lesser General Public License
  14. // along with SharpMap; if not, write to the Free Software
  15. // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
  16. using System;
  17. using System.Collections.Generic;
  18. using System.Text;
  19. namespace SharpMap.Web.Wms
  20. {
  21. /// <summary>
  22. /// This is a helper class designed to make it easy to create a WMS Service
  23. /// </summary>
  24. public class WmsServer
  25. {
  26. /// <summary>
  27. /// Generates a WMS 1.3.0 compliant response based on a <see cref="SharpMap.Map"/> and the current HttpRequest.
  28. /// </summary>
  29. /// <remarks>
  30. /// <para>
  31. /// The Web Map Server implementation in SharpMap requires v1.3.0 compatible clients,
  32. /// and support the basic operations "GetCapabilities" and "GetMap"
  33. /// as required by the WMS v1.3.0 specification. SharpMap does not support the optional
  34. /// GetFeatureInfo operation for querying.
  35. /// </para>
  36. /// <example>
  37. /// Creating a WMS server in ASP.NET is very simple using the classes in the SharpMap.Web.Wms namespace.
  38. /// <code lang="C#">
  39. /// void page_load(object o, EventArgs e)
  40. /// {
  41. /// //Get the path of this page
  42. /// string url = (Request.Url.Query.Length>0?Request.Url.AbsoluteUri.Replace(Request.Url.Query,""):Request.Url.AbsoluteUri);
  43. /// SharpMap.Web.Wms.Capabilities.WmsServiceDescription description =
  44. /// new SharpMap.Web.Wms.Capabilities.WmsServiceDescription("Acme Corp. Map Server", url);
  45. ///
  46. /// // The following service descriptions below are not strictly required by the WMS specification.
  47. ///
  48. /// // Narrative description and keywords providing additional information 
  49. /// description.Abstract = "Map Server maintained by Acme Corporation. Contact: webmaster@wmt.acme.com. High-quality maps showing roadrunner nests and possible ambush locations.";
  50. /// description.Keywords.Add("bird");
  51. /// description.Keywords.Add("roadrunner");
  52. /// description.Keywords.Add("ambush");
  53. ///
  54. /// //Contact information 
  55. /// description.ContactInformation.PersonPrimary.Person = "John Doe";
  56. /// description.ContactInformation.PersonPrimary.Organisation = "Acme Inc";
  57. /// description.ContactInformation.Address.AddressType = "postal";
  58. /// description.ContactInformation.Address.Country = "Neverland";
  59. /// description.ContactInformation.VoiceTelephone = "1-800-WE DO MAPS";
  60. /// //Impose WMS constraints
  61. /// description.MaxWidth = 1000; //Set image request size width
  62. /// description.MaxHeight = 500; //Set image request size height
  63. ///
  64. /// //Call method that sets up the map
  65. /// //We just add a dummy-size, since the wms requests will set the image-size
  66. /// SharpMap.Map myMap = MapHelper.InitializeMap(new System.Drawing.Size(1,1));
  67. ///
  68. /// //Parse the request and create a response
  69. /// SharpMap.Web.Wms.WmsServer.ParseQueryString(myMap,description);
  70. /// }
  71. /// </code>
  72. /// </example>
  73. /// </remarks>
  74. /// <param name="map">Map to serve on WMS</param>
  75. /// <param name="description">Description of map service</param>
  76. public static void ParseQueryString(SharpMap.Map map, Capabilities.WmsServiceDescription description)
  77. {
  78. if (map == null)
  79. throw (new ArgumentException("Map for WMS is null"));
  80. if (map.Layers.Count == 0)
  81. throw (new ArgumentException("Map doesn't contain any layers for WMS service"));
  82. if (System.Web.HttpContext.Current == null)
  83. throw (new ApplicationException("An attempt was made to access the WMS server outside a valid HttpContext"));
  84. System.Web.HttpContext context = System.Web.HttpContext.Current;
  85. //IgnoreCase value should be set according to the VERSION parameter
  86. //v1.3.0 is case sensitive, but since it causes a lot of problems with several WMS clients, we ignore casing anyway.
  87. bool ignorecase = true; 
  88. //Check for required parameters
  89. //Request parameter is mandatory
  90. if (context.Request.Params["REQUEST"] == null)
  91. { WmsException.ThrowWmsException("Required parameter REQUEST not specified"); return; }
  92. //Check if version is supported
  93. if (context.Request.Params["VERSION"] != null)
  94. {
  95. if (String.Compare(context.Request.Params["VERSION"], "1.3.0", ignorecase) != 0)
  96. { WmsException.ThrowWmsException("Only version 1.3.0 supported"); return; }
  97. }
  98. else //Version is mandatory if REQUEST!=GetCapabilities. Check if this is a capabilities request, since VERSION is null
  99. {
  100. if (String.Compare(context.Request.Params["REQUEST"], "GetCapabilities", ignorecase) != 0)
  101. { WmsException.ThrowWmsException("VERSION parameter not supplied"); return; }
  102. }
  103. //If Capabilities was requested
  104. if (String.Compare(context.Request.Params["REQUEST"], "GetCapabilities", ignorecase) == 0)
  105. {
  106. //Service parameter is mandatory for GetCapabilities request
  107. if (context.Request.Params["SERVICE"] == null)
  108. { WmsException.ThrowWmsException("Required parameter SERVICE not specified"); return; }
  109. if (String.Compare(context.Request.Params["SERVICE"], "WMS") != 0)
  110. WmsException.ThrowWmsException("Invalid service for GetCapabilities Request. Service parameter must be 'WMS'");
  111. System.Xml.XmlDocument capabilities = Wms.Capabilities.GetCapabilities(map, description);
  112. context.Response.Clear();
  113. context.Response.ContentType = "text/xml";
  114. System.Xml.XmlWriter writer = System.Xml.XmlWriter.Create(context.Response.OutputStream);
  115. capabilities.WriteTo(writer);
  116. writer.Close();
  117. context.Response.End();
  118. }
  119. else if (String.Compare(context.Request.Params["REQUEST"], "GetMap", ignorecase) == 0) //Map requested
  120. {
  121. //Check for required parameters
  122. if (context.Request.Params["LAYERS"] == null)
  123. { WmsException.ThrowWmsException("Required parameter LAYERS not specified"); return; }
  124. if (context.Request.Params["STYLES"] == null)
  125. { WmsException.ThrowWmsException("Required parameter STYLES not specified"); return; }
  126. if (context.Request.Params["CRS"] == null)
  127. { WmsException.ThrowWmsException("Required parameter CRS not specified"); return; }
  128. else if (context.Request.Params["CRS"] != "EPSG:" + map.Layers[0].SRID.ToString())
  129. { WmsException.ThrowWmsException(WmsException.WmsExceptionCode.InvalidCRS, "CRS not supported"); return; }
  130. if (context.Request.Params["BBOX"] == null)
  131. { WmsException.ThrowWmsException(WmsException.WmsExceptionCode.InvalidDimensionValue, "Required parameter BBOX not specified"); return; }
  132. if (context.Request.Params["WIDTH"] == null)
  133. { WmsException.ThrowWmsException(WmsException.WmsExceptionCode.InvalidDimensionValue, "Required parameter WIDTH not specified"); return; }
  134. if (context.Request.Params["HEIGHT"] == null)
  135. { WmsException.ThrowWmsException(WmsException.WmsExceptionCode.InvalidDimensionValue, "Required parameter HEIGHT not specified"); return; }
  136. if (context.Request.Params["FORMAT"] == null)
  137. { WmsException.ThrowWmsException("Required parameter FORMAT not specified"); return; }
  138. //Set background color of map
  139. if (String.Compare(context.Request.Params["TRANSPARENT"], "TRUE", ignorecase) == 0)
  140. map.BackColor = System.Drawing.Color.Transparent;
  141. else if (context.Request.Params["BGCOLOR"] != null)
  142. {
  143. try { map.BackColor = System.Drawing.ColorTranslator.FromHtml(context.Request.Params["BGCOLOR"]); }
  144. catch { WmsException.ThrowWmsException("Invalid parameter BGCOLOR"); return; };
  145. }
  146. else
  147. map.BackColor = System.Drawing.Color.White;
  148. //Get the image format requested
  149. System.Drawing.Imaging.ImageCodecInfo imageEncoder = GetEncoderInfo(context.Request.Params["FORMAT"]);
  150. if (imageEncoder == null)
  151. {
  152. WmsException.ThrowWmsException("Invalid MimeType specified in FORMAT parameter");
  153. return;
  154. }
  155. //Parse map size
  156. int width = 0;
  157. int height = 0;
  158. if (!int.TryParse(context.Request.Params["WIDTH"], out width))
  159. {
  160. WmsException.ThrowWmsException(WmsException.WmsExceptionCode.InvalidDimensionValue, "Invalid parameter WIDTH");
  161. return;
  162. }
  163. else if (description.MaxWidth > 0 && width > description.MaxWidth)
  164. {
  165. WmsException.ThrowWmsException(WmsException.WmsExceptionCode.OperationNotSupported, "Parameter WIDTH too large");
  166. return;
  167. if (!int.TryParse(context.Request.Params["HEIGHT"], out height))
  168. {
  169. WmsException.ThrowWmsException(WmsException.WmsExceptionCode.InvalidDimensionValue, "Invalid parameter HEIGHT");
  170. return;
  171. }
  172. else if (description.MaxHeight > 0 && height > description.MaxHeight)
  173. {
  174. WmsException.ThrowWmsException(WmsException.WmsExceptionCode.OperationNotSupported, "Parameter HEIGHT too large");
  175. return;
  176. }
  177. map.Size = new System.Drawing.Size(width, height);
  178. SharpMap.Geometries.BoundingBox bbox = ParseBBOX(context.Request.Params["bbox"]);
  179. if (bbox == null)
  180. {
  181. WmsException.ThrowWmsException("Invalid parameter BBOX");
  182. return;
  183. }
  184. map.PixelAspectRatio = ((double)width / (double)height) / (bbox.Width / bbox.Height);
  185. map.Center = bbox.GetCentroid();
  186. map.Zoom = bbox.Width;
  187. //Set layers on/off
  188. if (!String.IsNullOrEmpty(context.Request.Params["LAYERS"])) //If LAYERS is empty, use default layer on/off settings
  189. {
  190. string[] layers = context.Request.Params["LAYERS"].Split(new char[] { ',' });
  191. if(description.LayerLimit>0)
  192. {
  193. if (layers.Length == 0 && map.Layers.Count > description.LayerLimit ||
  194. layers.Length > description.LayerLimit)
  195. {
  196. WmsException.ThrowWmsException(WmsException.WmsExceptionCode.OperationNotSupported, "Too many layers requested");
  197. return;
  198. }
  199. }
  200.                     foreach (SharpMap.Layers.ILayer layer in map.Layers)
  201. layer.Enabled = false;
  202.                     foreach (string layer in layers)
  203.                     {
  204.                         //SharpMap.Layers.ILayer lay = map.Layers.Find(delegate(SharpMap.Layers.ILayer findlay) { return findlay.LayerName == layer; });
  205.                         SharpMap.Layers.ILayer lay = null;
  206.                         for (int i = 0; i < map.Layers.Count; i++)
  207.                             if (String.Equals(map.Layers[i].LayerName, layer, StringComparison.InvariantCultureIgnoreCase))
  208.                                  lay = map.Layers[i];
  209.                         
  210.                         
  211.                         
  212.                         
  213.                         if (lay == null)
  214. {
  215. WmsException.ThrowWmsException(WmsException.WmsExceptionCode.LayerNotDefined, "Unknown layer '" + layer + "'");
  216. return;
  217. }
  218. else
  219. lay.Enabled = true;
  220.                     }
  221. }
  222. //Render map
  223. System.Drawing.Image img = map.GetMap();
  224. //Png can't stream directy. Going through a memorystream instead
  225. System.IO.MemoryStream MS = new System.IO.MemoryStream();
  226. img.Save(MS, imageEncoder, null);
  227. img.Dispose();
  228. byte[] buffer = MS.ToArray();
  229. context.Response.Clear();
  230. context.Response.ContentType = imageEncoder.MimeType;
  231. context.Response.OutputStream.Write(buffer, 0, buffer.Length);
  232. context.Response.End();
  233. }
  234. else
  235. WmsException.ThrowWmsException(WmsException.WmsExceptionCode.OperationNotSupported, "Invalid request");
  236. }
  237. /// <summary>
  238. /// Used for setting up output format of image file
  239. /// </summary>
  240. private static System.Drawing.Imaging.ImageCodecInfo GetEncoderInfo(String mimeType)
  241. {
  242. foreach(System.Drawing.Imaging.ImageCodecInfo encoder in System.Drawing.Imaging.ImageCodecInfo.GetImageEncoders())
  243. if (encoder.MimeType == mimeType)
  244. return encoder;
  245. return null;
  246. }
  247. /// <summary>
  248. /// Parses a boundingbox string to a boundingbox geometry from the format minx,miny,maxx,maxy. Returns null if the format is invalid
  249. /// </summary>
  250. /// <param name="strBBOX">string representation of a boundingbox</param>
  251. /// <returns>Boundingbox or null if invalid parameter</returns>
  252. private static SharpMap.Geometries.BoundingBox ParseBBOX(string strBBOX)
  253. {
  254. string[] strVals = strBBOX.Split(new char[] {','});
  255. if(strVals.Length!=4)
  256. return null;
  257. double minx = 0; double miny = 0;
  258. double maxx = 0; double maxy = 0;
  259. if (!double.TryParse(strVals[0], System.Globalization.NumberStyles.Float, SharpMap.Map.numberFormat_EnUS, out minx))
  260. return null;
  261. if (!double.TryParse(strVals[2], System.Globalization.NumberStyles.Float, SharpMap.Map.numberFormat_EnUS, out maxx))
  262. return null;
  263. if (maxx < minx)
  264. return null;
  265. if (!double.TryParse(strVals[1], System.Globalization.NumberStyles.Float, SharpMap.Map.numberFormat_EnUS, out miny))
  266. return null;
  267. if (!double.TryParse(strVals[3], System.Globalization.NumberStyles.Float, SharpMap.Map.numberFormat_EnUS, out maxy))
  268. return null;
  269. if (maxy < miny)
  270. return null;
  271. return new SharpMap.Geometries.BoundingBox(minx, miny, maxx, maxy);
  272. }
  273. }
  274. }