使用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>
View Code

(5)创建IIS宿主服务

       a.创建应用程序池,目标平台.net4.0,应用32位应用程序=True,这个很重要,因为服务是32位的。

       b.在默认网站下,添加应用程序目标,指向网站目录。

(6)测试

       a.由于坐标字符串生成shapefile文件时,前台给生成传入的字符串比较多,只能使用POST请求,而且还需要在配置文件中添加如下配置信息:

      <webHttpBinding>
        <binding name="webHttpBinding_Default" maxReceivedMessageSize="2147483647" />
      </webHttpBinding>

        b.使用fiddler测试,选择Composer页,见下图:

 

posted @ 2017-05-02 15:25  SimpleGIS  阅读(558)  评论(0编辑  收藏  举报