本文主要是介绍ArcServer SOE 入坑指南,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
声 明1 : 本人才疏学浅,用郭德纲的话说“我是一个小学生”,如有错误,欢迎讨论,请勿谩骂^_^。
声 明2 : 原创博客请在转载时保留原文链接或在文章开头加上本人博客地址,否则保留追究法律责任的权利。
欢迎加群: GIS开发部落
源起
记录SOE开发的学习笔记&各种坑,本文使用的ArcServer版本为10.3,使用的编程语言C#。如果你觉得本文对你有用,请不要吝惜你的夸奖,给个点赞+好评+收藏吧!
SOE资源
- ArcGIS Server使用
- suwenjiang的烂笔头-SOE专题
- ArcGIS for Server的SOE开发思路解析
- Walkthrough for Creating a REST Server Object Extension
- 地理处理服务设置:池化和进程
- 调整和配置服务
- ServerAdminToolkit(SOE的上传和注册脚本)
- ArcGIS Enterprise SDK GitHub示例代码
- ArcGIS Enterprise SDK
SOE开发
SOE适用场景
以下仅代表个人的一些观点:
- 如果您希望执行一些定义良好的业务逻辑来处理 GIS 数据和服务,而这些业务逻辑使用现有服务 API 不容易完成,那么 SOE 是合适的。(
简单而言适用于后台处理GIS数据并对外提供接口
) - 对Server端GP扩展开发不熟悉的但是对AE开发比较熟悉的,可以尝试考虑SOE开发。
- GP适合复杂业务流程,较低并发下的应用 ,SOE适合单一功能的模块,较高并发下的应用。
- 适合将CS程序转型到BS模式
- 对外提供Rest接口操作GIS数据
举几个我这边应用过的场景:
- 路网地图数据的审核
- 上下两年地图数据对比分析
- 基于遥感影像数据识别路网分析上报路网的真实性
- 批量出图
- 下载地图数据
开发环境
SOE开发你需要安装ArcServer、ArcObject、C#/Java的开发环境、数据库环境(这块我使用的是VS,10.3使用vs2013即可,10.6.1使用vs2017即可
)
具体区别:
C#: 不支持部署在Linux机器上,开发部署简单。(本文主要针对C#语言
)
Java:跨平台,支持部署在Linux机器上,开发环境搭建复杂。
注意:开发需要AO的环境,装完ArcObjects就可以在VS工程模板中找到对应的SOE模板了,部署机器有ArcServer即可,不需要AO环境。
SOE数据源
- 可以使用本地的GDB、SDE、地图服务获取数据,但是从本地GDB和SDE直接读取数据目前存在bug,会遇到内存无法释放的问题。
- 建议从地图服务中读取所需要的数据,在程序初始化执行Construct函数的时候,直接预先一次性读取或者打开工作空间。
- 不支持MDB,这块文章下面有详细的说明。
SOE开发过程
开发前建议先理清你的业务,比如以下几个方面:
- 你的数据来源于哪儿?本地还是共享目录
- 你的数据格式是啥?shp、gdb、sde?
- 你读取数据的方式?直接AE代码操作读取还是从地图服务读取?还是混合读取?
- 你的数据处理完了存储到哪儿?本地or共享目录or数据库or内存or其它中间存储(Redis)
- 调用你的SOE接口是否需要他人等待结束(即同步执行)or不需要等待(异步执行)?
- 你的业务是否对并发有要求?
- 你的业务是否使用前端已有的接口无法直接完成?
SOE开发示例(待补充)
- 新建SOE工程
- 修改SOE的名称和类型
- 编写SOE的的基本信息
- 编写SOE的主题函数(参数、函数)
- 编辑生成SOE文件
- 部署测试
待补充
SOE过程详解
- MapServer初始化
- SOE初始化
- MapServer启动
- SOE构造
- SOE活动——REST/SOAP处理请求——SOE停止活动
- MapServer停止
- SOE关闭
SOE接口详解
待补充
SOE调试技巧
- 打开VS程序->调试->附加到进程,选择所有的ArcSOC.exe,然后调试(这块只需要附加托管的exe)。
- 在init函数中添加代码
System.Diagnostics.Debugger.Launch();
,SOE初始化完毕后,就会弹出窗体,询问你是否启动VS工程或者附加到当前打开的VS工程进行调试。当然了你也可以把该句代码放到任何你想调试的地方,初始部署的时候,他会自动打断点到该句代码所在的位置。 - 使用PostMan或者直接访问网页请求测试。
- SOE最好是现在本地测试好后,然后再部署到服务器上,这块本地测试如果使用winform或者控制台程序,需要添加初始化许可的代码。
- LZ本人是使用C#开发的SOE,这块记录日志采用log4net,默认SOE的程序启动路径就是server的启动目录(如:C:\Program Files\ArcGIS\Server\bin),如果log4net这块配置的是相对路径,默认情况下日志是存在该目录下。
SOE 开发技巧
-
SOE传参这块提供获取参数的方法有如下这些:
TryGetArray、TryGetAsBoolean、TryGetAsDate、TryGetAsDouble、TryGetAsLong、TryGetJsonObject、TryGetObject、TryGetString
,具体的使用过程不做介绍。下面说一下传参这块的坑吧:
如果你想传string,但是你界面输入的是230000
(类似这种数字的),后台是按照long类型处理的,使用TryGetString是无法取到值的,只要230000,21000
这种的,后台才会按照string处理,如果你的参数实际上可能是数值类型也可能是字符串类型,这个时候你可能就需要同时用到上面的TryGetAsLong、TryGetString
两个方法来获取输入的参数。 -
建议从地图服务获取数据源
,不建议从本地gdb或者sde直接读取数据, -
不建议使用多线程
,通过增加ArcSOC的实例数可以更好的并发。 -
建议控制好Com对象的释放
,避免多个用户调用的时候内存占用严重,遇到大数据有可能会导致服务器卡顿、死机。 -
建议记录日志
,比如使用log4net记录程序运行中的日志,方便更好的查找修改bug,记录日志。 -
不同版本的ArcServer,需要编译不同版本的SOE程序
,这块在迁移的时候,有时候工程需要重新创建,然后再添加之前已有的类,最后重新引用编译即可。
SOE部署
SOE部署所需环境
- ArcServer Windows版本
- ArcServer许可
- .net framework环境(针对C#开发者)
SOE部署步骤
- 程序编译好后的.soe文件,可以使用360压缩软件打开查看,可以理解为soe文件就是类似zip的一个压缩包文件,里头放着soe运行需要的dll xml等配置文件。
- 大概ArcGis Server Manager->登录
- 选择站点->扩展->添加扩展->选择编译好的soe文件
- 服务->选择指定的服务->选择功能->勾选SOE扩展
- 查看soe扩展的rest地址
地图服务参数配置
建议将池化中ArcSOC.exe实例个数修改一下,最大设置为n+1(n为计算机最大核心数),具体个数可以自己调优测试。
SOE部署注意事项
- SOE开发使用的server版本需要和部署机器上server版本一致,如:如果你是用10.3开发的SOE,你想在arcserver10.8环境下使用,那么你必须要10.8环境新建soe模板,拷贝相关代码然后重新编译。
- .net framework版本需要一致。
- SOE开发本身不需要AO初始化许可那一套,但是本地使用控制台或者winform测试的时候,还是需要初始化许可的。
- Server集群后,SOE部署的方式本身没有发生变化,SOE正常部署完毕会自动拷贝到server的目录中。(关于集群请看这里:传送门)
SOE详解
SOE Rest地址详解
SOE调用
调用Rest服务参考官方帮助,此处略。
地图服务相关知识
- 对地图服务指定多个实例数来处理多个请求,如果设置实例数10,那么当来了20个任务的时候,后台会启动10个Arcsoc.exe进程,前10个任务不需要排队,后10个任务需要排队执行。
- SOE默认超时时间600秒,如果这块设置的过短,就会出现超时的问题。
- 关于SOE集群,SOE集群可以增加ArcSOC.exe进程的个数,间接的增加了SOE并行处理任务的能力。
- SOE集群部署方面,只需在webAdapter这块添加扩展,集群的机器会自动将soe文件拷贝到各自机器上的server目录下
问题记录
1. arcgis server manager 添加SOE扩展失败问题
这块切换到IE浏览器即可解决!
2. SOE 部署错误 ClassFactory cannot supply requested class问题及解决方案
1. 确保.net 扩展支持(我基于.net开发的),这块是在安装ArcServer的时候勾选的。
2. SDK版本检查,确保ArcServer机器的AO版本和开发环境的AO版本一致。
3. 确保.net framework的版本和Arcobjects默认支持的版本一致,迁移到高版本时可能需要重新新建工程导入代码再编译测试。
4. 是否兼容了64位检查,这块建议设置成AnyCPU。
3. PostMan请求不到接口问题
4. SOE 中调用第三方dll
- SOE 中调用第三方dll
- VS2013外部工具中添加ildasm.exe
- 为VS2012集成IL工具
5. SOE不能进入断点调试
6. SOE删除不彻底的解决方案
参考博文SOE for .Net中重新编译生成新的.soe后无法识别的解决方法
- 在ArcGIS Server Manager的服务->功能列表中,取消勾选SOE扩展,并重启服务。
- 在ArcGIS Server Manager的站点->扩展列表中,删除SOE扩展。
- 在arcgis manager的管理页面中检查扩展是否删除(
http://localhost:6080/arcgis/admin
)- Home->services->types->extensions ->unregister(取消注册要注册的soe文件)
- Home-> uploads-> 删除要删除的soe文件
- 检查本地目录中是否存在SOE相关的文件,存在则手动删除。
- 删除目录下的内容:C:\arcgisserver\directories\arcgissystem\arcgisuploads\admin
- 删除目录下的内容:C:\arcgisserver\config-store\extns
- 删除目录C:\Users\arcgis\AppData\Local\ESRI\Server10.3\AssemblyCache下的包含SOE相关程序的文件夹)
- 检查一下ServerTypesExt.dat文件的内容,如果不涉及之前的SOE,则不删除也可以。
- 删除目录
C:\Program Files\ArcGIS\Server\bin
下的文件ServerTypesExt.dat
- 删除目录
7. SOE不能使用ComReleaser管理Com对象,报错如下:
“未能加载文件或程序集“ESRI.ArcGIS.ADF, Version=10.4.0.0, Culture=neutral,
PublicKeyToken=8fc3cc631e44ad86”或它的某一个依赖项。系统找不到指定的文件”
解决方案:使用函数System.Runtime.InteropServices.Marshal.ReleaseComObject
释放Com对象。
8. 10.3版本的SOE扩展访问地址是基于Http请求的,使用6080端口,10.8版本的SOE扩展访问地址是基于Https的,使用6443端口,这块这块调用略有不同,10.8版本的需要准备证书,解决方案: Server端配置证书。
- 使用默认自签名证书配置 ArcGIS Server
- ArcGIS Server将http改为https
9. SOE报错Out of server memory
:
-
数据源不建议直接使用gdb或者sde库,数据源建议通过地图服务获取数据,通过gdb和sde读取内存难以释放,这块已经测试发现SOE存在这块的bug。除此之外建议在SOE初始化的时候,在Construct函数中获取数据源,后面直接使用。
-
增加ArcSOC的实例数,之前我这块一直设置的默认参数,每次就一个ArcSOC.exe,多个请求过来的时候一般都会排队等待
-
SOE本身支持多用户请求,他会自己将请求分配到ArcSOC.exe上,所以SOE程序内部不需要再写成多线程的形式,写成多线程有个问题就是,线程之间无法传递AO对象,AO对象需要序列化和反序列化,这样有个弊端就是内存还是会飙涨,回头内存释放还是存在问题。
- 增加SOC的内存,具体参考博文:传送门
- 完善代码,对Com对象(Ifeaturecursor、IFeatureClass、IFeature等Com对象)、以及其他占内存的对象(Datatable、DataReader)进行管理,不用的时候释放掉。
GC.WaitForPendingFinalizers()
会导致服务器端程序被挂起,这块建议不使用此句代码,避免程序被长时间挂起。
-
ArcSOC 实例的数量导致 ArcGIS Server 性能问题
10. 服务超时问题
Processing request took longer than the usage timeout for service 'SOETest.MapServer'. Server request timed out. Check that the usage timeout is appropriately configured for such requests.
解决方案:将指定服务使用的超时时间调大。
11. 客户端请求多个服务,实际返回部分结果,部分请求挂掉无返回结果。
解决方案:将指定服务的获取服务等待的时间调大。
12. 10.3 ArcServer 添加SOE成功,但是在地图服务开启SOE扩展,访问SOE的Rest地址老是提示soe文件找不到
解决方案:暂时是重启地图服务解决的
13. SOE程序在共享目录(SMB2协议)上创建GDB,报错Cannot acquire a lock
解决方案:传送门
1. 以计算机管理员的身份,打开开始菜单并键入 regedit.exe 以打开注册表编辑器。
导航到以下注册表项:
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\Lanmanworkstation\Parameters
2. 检查项中是否存在名称 DirectoryCacheLifetime。
3. 如果该名称不存在,请创建一个新的 32 位 DWORD(右键单击并选择新建 > DWORD 值)并将其命名为 DirectoryCacheLifetime。
名称 DirectoryCacheLifetime 存在后,请将 DWORD 值修改为 0。
14. SOE调用本地数据资源,内存持续增长不释放
解决方案:杀进程
//以下代码仅供参考,大神轻喷
GC.Collect();
var process = System.Diagnostics.Process.GetCurrentProcess();
process.Close();
process = System.Diagnostics.Process.GetCurrentProcess();
process.Kill();
process.WaitForExit(100);
15. GDB只读,SOE在GDB中创建表报错,参考:传送门
解决方案:如果你地图服务中使用了gdb中的图层,那么你只能通过接口获取图层并对其进行编辑操作。如果你地图服务中没使用gdb中的图层,那么你可以直接用SOE打开工作空间并对图层做编辑。
If you want to edit the map service’s data source using IMapServerDataAccess.GetDataSource
, your map service’s data source needs to be in a registered enterprise geodatabase (you don’t have to check the Feature Access capability though).
If your map service’s data source is from a file geodatabase, registered folder, or copied to server, then the service’s data is not editable via SOE/SOI, because the service itself in this case is read-only and not editable, and so is the service’s data source/workspace.
However, you can edit data (such as a file gdb feature class) in SOE/SOI via direct access to the data through WorkspaceFactory (such as IWorkspaceFactory.OpenFromFile
), instead of the service access (IMapServerDataAccess.GetDataSource). In this scenario, your arcgis server account must have permission to access the data (such as the .gdb), in other words, the data must be at a location where server account has permission to access.
16. SOE调用字段计算器报错,不支持VB脚本
解决方案:使用python脚本代替VB脚本
17. SOE操作本地GDB,修改编辑图层失败
添加修改图层需要对GDB文件夹有编辑权限
18. 添加SOE后服务无法启动的几种可能原因
19. SOE出图
```
[DllImport("user32.dll", EntryPoint = "GetDesktopWindow")]protected static extern IntPtr GetDesktopWindow();/// <summary>/// 得到系统窗口的句柄,传递给mxd用作激活窗口用途/// </summary>/// <returns></returns>private int GetWinhWnd(){int hWnd = GetDesktopWindow().ToInt32();return hWnd;}private void ExportImg(){//打开mxdstring appPath = System.IO.Path.GetDirectoryName(this.GetType().Assembly.Location);string mxdPath = System.IO.Path.Combine(appPath, Catsic.Sys.ConstDef.C_MAP_TEMPLATE);IMapDocument pMapDocument = new MapDocumentClass();pMapDocment.Open(mxdPath);//mxd替换数据源(略)//激活地图IActiveView pActiveView = pMapDocument.ActiveView;pActiveView.Activate(GetWinhWnd()); //此处代码略,请自行百度,找不到的留言。//设置地图范围(略)//出图(略) }
```
20. 深坑之soe文件无法生成
VS2013上编译没问题,切换到VS2017时编译错误
未找到“GenerateServerAddInXml”任务。请检查下列各项:
1.)项目文件中的任务名称与任务类的名称相同。
2.)任务类为“public”且实现 Microsoft.Build.Framework.ITask 接口。
3.)在项目文件中或位于“D:\Program Files (x86)\Microsoft Visual
Studio\2017\Community\MSBuild\15.0\Bin”目录的 *.tasks 文件中使用 <UsingTask> 正确声明了该任务。 Catsic.GLSLTZJHXT.ExportDataSOE
解决方案:
找到*.csproj文件,对其编辑
21. SOE不支持MDB
错误:错误:类未注册(HRESULT 出现异常:0x80040154 (REGDB_E_CLASSNOTREG)
解决方案:使用shp、gdb、sde代替mdb。
22. 利用SOE实现下载文件
参考代码:传送门
responseProperties = "{\"Content-Type\" : \"application/octet-stream\",\"Content-Disposition\": \"attachment; filename=" + fileName + "\"}";
return System.IO.File.ReadAllBytes(filePath);
23. 调用SOE接口时跨域问题的解决方案
参考:什么是跨域?跨域解决方法
方法1:前端使用jsonp
的get
请求
方法2:soe端设置Access-Control-Allow-Origin
responseProperties = "{\"Content-Type\" : \"application/json\",\"Access-Control-Allow-Origin\":\"*\"}";
方法3:使用nginx代理
24. SOE接收参数乱码的解决就方案
参考:c# UrlEncode,UrlDecode
HttpUtility.UrlEncode(text, System.Text.Encoding.GetEncoding("utf-8"));
25. VS2012中编译10.2版本的的SOE模板无法生成.soe文件
26. SOE属性配置BUG
当在同一个server上的两个SOE配置相同名称的属性时,第二个配置的会被忽略。
解决方案:避免使用同名的属性参数。
NIM089714 - When running two Server Object Extensions (SOEs) on the same server with the same property name, the value of the second SOE property is ignored.
实际部署过程中,我发现配置页面修改属性时无效,最后直接把配置参数写入到代码中编译部署的。
27. System.IO.File.Copy调用时会产生锁,如果是多个请求同时拷贝同一个文件会出bug
解决方案:
using (System.IO.FileStream source = new System.IO.FileStream(item.FullName, System.IO.FileMode.OpenOrCreate, System.IO.FileAccess.Read, System.IO.FileShare.Read))
{using (System.IO.Stream destination = System.IO.File.Create(localShpFilePath)){source.CopyTo(destination);}
}
28. System.InvalidOperationException: DataReader.GetFieldType(101) 返回了 null
原因:表使用了geography(地理)字段
解决方案:参考https://stackoverflow.com/questions/6569624/datareader-getfieldtype-returned-null
①可以把select * 换成具体的字段 ②拷贝想要的Microsoft.SqlServer.Types.dll到bin目录
29.ArcGIS Server打补丁
解决方案:找一台有网络的机器(方便访问Esri官方网站),打开【开始】->【ArcGIS】->【Check for Updates】
可以看到当前Server版本的相关补丁,可以点开具体链接查看补丁的相关信息
Server补丁在线下载地址:传送门
30.解决ArcGIS Server 卡顿的bug
版本:10.3.0
卡顿原因:10.3.0自身bug
解决方案:下载相关补丁(主要是下面链接中的第二个)
ArcGIS Server 地理处理服务启动补丁
ArcGIS 10.3 for Server 站点创建失败及服务启动性能补丁
ArcGIS 10.3 (Desktop, Engine, Server) Geodesic Buffer 方法补丁
Java开发环境搭建参考资料
- 官方帮助
- ArcGIS SOE 04使用Eclipse IDE
- Arcobject for java 开发环境配置(IDEA)
- 03-Install the Java IDE
- 05-Build REST SOEs using IntelliJ
- Java环境下AO开发之环境部署及注意事项(eclipse平台)
- ae(ArcEngine) java swing开发入门系列(1):开发环境和代码部署
- ArcGIS Engine 10.5下构建Java程序—轻松入门
这篇关于ArcServer SOE 入坑指南的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!