使用wcf编写坐标字符串生成shapefile文件,在iis发布供前端调用
项目有一需求,需要由坐标字符串(格式:x,y,点名)生成shapefile,由于在前台开发类似功能比较麻烦而且也不适用,最终决定使用WCF来实现,不借助现有GIS软件,基于GDAL实现。
实现过程如下:
编写坐标对生成shapefile的坐标,并使用zipHelper将shapefile压缩成zip文件,返回前端下载,整个代码如下:
(1)编写坐标转换服务代码
[Description("坐标服务接口")] [ServiceContract] public interface ICoord2Shapefile { //[WebGet(UriTemplate = "{points}", ResponseFormat = WebMessageFormat.Json)] [WebInvoke(Method = "POST", ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Bare, RequestFormat = WebMessageFormat.Json,UriTemplate="/")] [Description("将坐标生成shapefile,并压缩打包")] [OperationContract] string point2zip(string points); } [ServiceBehavior(AddressFilterMode = AddressFilterMode.Any)] [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)] public class Coord2ShapefileService : ICoord2Shapefile { public string point2zip(string points) { LogHelper.Info(points); string zip = ""; //List<Location> locs = JsonHelper.DeserializeJsonToList<Location>(points); try { List<Location> locs = new List<Location>(); string[] pps = points.Split(';'); for (int i = 0; i < pps.Length; i++) { string[] pp = pps[i].Split(','); double x = Convert.ToDouble(pp[0]); double y = Convert.ToDouble(pp[1]); Location loc = new Location() { X = x, Y = y, Name = pp[2] }; locs.Add(loc); } if (locs != null && locs.Count > 0) { LogHelper.Info(string.Format("{0} 个点",locs.Count)); string shpfile = Path.GetTempFileName(); shpfile = shpfile.Substring(0, shpfile.Length - 3) + "shp"; LogHelper.Info(shpfile); //shpfile = "e:\\aa.shp"; WriteVectorFileShp(shpfile, locs); if (File.Exists(shpfile)) { FileInfo fileinfo = new FileInfo(shpfile); DirectoryInfo dirInfo = fileinfo.Directory; string shpName = Path.GetFileNameWithoutExtension(shpfile); List<string> files = new List<string>(); files.Add(shpfile); files.Add(Path.Combine(dirInfo.FullName, shpName + ".prj")); files.Add(Path.Combine(dirInfo.FullName, shpName + ".dbf")); files.Add(Path.Combine(dirInfo.FullName, shpName + ".shx")); //string zipFile = "d:\\point.zip"; string id = Guid.NewGuid().ToString(); string zipFile = string.Format("d:\\update\\temp\\{0}{1}{2}{3}{4}{5}{6}.zip", DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day, DateTime.Now.Hour, DateTime.Now.Minute, DateTime.Now.Second, DateTime.Now.Millisecond); //string zipFile = string.Format("d:\\{0}{1}{2}{3}{4}{5}{6}.zip", DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day, DateTime.Now.Hour, DateTime.Now.Minute, DateTime.Now.Second, DateTime.Now.Millisecond); //string zipFile = "www.simplemap.com.cn/update/temp"; int ret = ZipHelper.ZipFiles(zipFile, files.ToArray(), "data"); if (ret > 0) { foreach (var file in files) { try { File.Delete(file); } catch (Exception) { } } if (File.Exists(zipFile)) { FileInfo ff = new FileInfo(zipFile);zip = "http://localhost/temp" + ff.Name; } } } else { LogHelper.Info(string.Format("{0} 不存在!", shpfile)); } } } catch (Exception ex) { LogHelper.Error(ex.Message, ex); } return zip; } static void WriteVectorFileShp(String shapefile_path, List<Location> locs) //创建算法生产的边界矢量图 { // 为了支持中文路径,请添加下面这句代码 OSGeo.GDAL.Gdal.SetConfigOption("GDAL_FILENAME_IS_UTF8", "NO"); // 为了使属性表字段支持中文,请添加下面这句 OSGeo.GDAL.Gdal.SetConfigOption("SHAPE_ENCODING", ""); // 注册所有的驱动 Ogr.RegisterAll(); LogHelper.Info("注册GDAL成功"); //创建数据,创建ESRI的shp文件 string strDriverName = "ESRI Shapefile"; Driver oDriver = Ogr.GetDriverByName(strDriverName); if (oDriver == null) { Debug.WriteLine("%s 驱动不可用!\n", shapefile_path); return; } // 步骤1、创建数据源 DataSource oDS = oDriver.CreateDataSource(shapefile_path, null); if (oDS == null) { Debug.WriteLine("创建矢量文件【%s】失败!", shapefile_path); return; } LogHelper.Info("创建矢量文件成功"); //步骤2、创建空间坐标系 OSGeo.OSR.SpatialReference oSRS = new OSGeo.OSR.SpatialReference(""); oSRS.SetWellKnownGeogCS("WGS84"); //步骤3、创建图层,并添加坐标系,创建一个多边形图层(wkbGeometryType.wkbUnknown,存放任意几何特征) Layer oLayer = oDS.CreateLayer("地名", oSRS, wkbGeometryType.wkbPoint, null); if (oLayer == null) { Debug.WriteLine("图层创建失败!"); return; } // 步骤4、下面创建属性表 FieldDefn oFieldPlotArea = new FieldDefn("Name", FieldType.OFTString); // 先创建一个叫PlotArea的属性 oFieldPlotArea.SetWidth(100); // 步骤5、将创建的属性表添加到图层中 oLayer.CreateField(oFieldPlotArea, 1); //步骤6、定义一个特征要素oFeature(特征要素包含两个方面1.属性特征2.几何特征) foreach (var loc in locs) { FeatureDefn oDefn = oLayer.GetLayerDefn(); Feature oFeature = new Feature(oDefn); //建立了一个特征要素并将指向图层oLayer的属性表 //步骤7、设置属性特征的值 oFeature.SetField(0, loc.Name); OSGeo.OGR.Geometry pt = new Geometry(wkbGeometryType.wkbPoint); pt.AddPoint(loc.X, loc.Y, 0); oFeature.SetGeometry(pt); //OSGeo.OGR.Geometry geomTriangle = OSGeo.OGR.Geometry.CreateFromWkt(wkt);//创建一个几何特征 //步骤8、设置几何特征 //oFeature.SetGeometry(geomTriangle); //步骤9、将特征要素添加到图层中 oLayer.CreateFeature(oFeature); } oDS.Dispose(); LogHelper.Info("数据集创建完成!"); //Debug.WriteLine("数据集创建完成!"); } } public class Location { public double X { get; set; } public double Y { get; set; } public string Name { get; set; } }
(2)由于GDAL只能在x86下使用,将目标平台编译成x86。
(3)创建一个空网站,添加Service.svc服务文件,内容如下:
<%@ ServiceHost Language="C#" Debug="true" Service="CoordService.Coord2ShapefileService" %>
(4)设置web.config的配置文件
<configuration> <configSections> <section name="log4net" type="System.Configuration.IgnoreSectionHandler"/> </configSections> <log4net> <appender name="LogFileAppender" type="log4net.Appender.FileAppender"> <file type="log4net.Util.PatternString" value="%logger\%date{yyyy-MM-dd}\log.txt"/> <layout type="log4net.Layout.PatternLayout"> <conversionPattern value="%date %-5level %message%newline"/> </layout> </appender> <root> <appender-ref ref="LogFileAppender"/> </root> <logger name="Logger" additivity="false"> <level value="All"/> <appender-ref ref="LogFileAppender"/> </logger> </log4net> <system.web> <compilation debug="true" targetFramework="4.0" /> </system.web> <system.serviceModel> <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true"> </serviceHostingEnvironment> <services> <!--behaviorConfiguration属性开通服务的元数据发布服务,无此属性,服务的元数据发布无法使用,但服务中的功能可以调用--> <service name="CoordService.Coord2ShapefileService" behaviorConfiguration="metadataExchange"> <!--终结点不加behaviorConfiguration属性,无法调用服务中的功能,会出现“由于 AddressFilter 在 EndpointDispatcher 不匹配”的错误--> <endpoint address="" binding="webHttpBinding" bindingConfiguration="webHttpBinding_Default" contract="CoordService.ICoord2Shapefile" behaviorConfiguration="webHttp"/> </service> </services> <bindings> <webHttpBinding> <binding name="webHttpBinding_Default" maxReceivedMessageSize="2147483647" /> </webHttpBinding> </bindings> <behaviors> <!--开通服务的元数据发布--> <serviceBehaviors> <behavior name="metadataExchange"> <!-- 为避免泄漏元数据信息,请在部署前将以下值设置为 false --> <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/> <!-- 要接收故障异常详细信息以进行调试,请将以下值设置为 true。在部署前设置为 false 以避免泄漏异常信息--> <serviceDebug includeExceptionDetailInFaults="false"/> </behavior> </serviceBehaviors> <endpointBehaviors> <behavior name="webHttp"> <webHttp helpEnabled="True"/> </behavior> </endpointBehaviors> </behaviors> </system.serviceModel> </configuration>
(5)创建IIS宿主服务
a.创建应用程序池,目标平台.net4.0,应用32位应用程序=True,这个很重要,因为服务是32位的。
b.在默认网站下,添加应用程序目标,指向网站目录。
(6)测试
a.由于坐标字符串生成shapefile文件时,前台给生成传入的字符串比较多,只能使用POST请求,而且还需要在配置文件中添加如下配置信息:
<webHttpBinding> <binding name="webHttpBinding_Default" maxReceivedMessageSize="2147483647" /> </webHttpBinding>
b.使用fiddler测试,选择Composer页,见下图: