1.1 必選接口
1.1.1 IRESTRequestHandler 接口
該接口主要有下面兩個方法:
string GetSchema(); byte[] HandleRESTRequest()
1.1.1.1 IRESTRequestHandler.handleRESTREquest() 方法主要有下面
兩個作用:
回調資源和操作的方法
獲取資源在實例級別的描述該方法在識別這兩個作用的時候是通過operationName參數,如果該參數是空字符產那就是第二個作用,否則是第一個作用。
該方法的參數如下:
1. String capabilities:一組被資源授權的操作,可以爲空字符串
2. String resourceName: 資源名稱. 空字符串表示根級別,子資源會通過
‘/’ 表示
3. String operationName: 操作名稱
4. String operationInput: 操作的參數,JSON格式
5. String outputFormat:客戶端請求的輸出格式,如JSON,AMF
6. String[] responseProperties: 通過操作返回的一組鍵值對,逗號分開 1.1.1.2 IRESTRequestHandler.getSchema() 方法
以 JSON 格式返回 SOE 的資源列表
1.1.2 IServerObjectExtension
該接口主要有個方法:Init(IServerObjectHelper pSOH)和void Shutdown();
當Server啓動的時候會調用該方法,並將IServerObjectHelper對象傳入,該接口是對Server對象的弱引用,可以通過IServerObjectHelper.ServerObject得到服務器對象。 Shutdown方法用在服務器關閉時調用,經常我們在該方法中釋放SOE中使用的資源。
1.2 可選接口
1.2.1 IObjectConstruct
該接口只有一個方法Construct,該方法在Init方法執行後,立即被執行,如果我們的SOE有配置屬性,就可通過該方法的參數得到,該方法只調用1次,我們可以將SOE中用的的比較耗費資源的邏輯寫在該方法中,比如:獲取地圖代碼,或者你始終操作某一個圖層,就可以把獲取該圖層的代碼寫在這裏。
1.2.2 IObjectActivate
當 init 和 Construct 調用後,SOE 的對象已經被創建,並且相應的配置信息也得到了,如果 SOE 的整個邏輯中需要不停的獲取和釋放服務器上下文,那麼就必須實現改接口,改接口有兩個方法: activate()和 deactivate(),當客戶端調用CreateServerContext() 的時候 activate()方法被調用,當客戶端釋放服務器上下文對象時 deactivate()方法被調用。
SOE 的執行過程
在對接口介紹的時候,我們已經提到了 SOE 的的運行過程,我們通過下面
的圖可進一步瞭解:
1.3 創建SOE
現在我們創建一個完整的SOE,在 VS2010 中新建一個項目,選擇 Server
Object Extention,並在右邊選擇REST 模板,如下圖:
當點了確定之後,我們可以看到VS 已經爲我們生成了一個 RestSOETest 的類,該類已經實現了了我們前面介紹過的接口,如下:
public class RestSOETest : IServerObjectExtension, IObjectConstruct, IRESTRequestHandler
{
private string soe_name;
private IPropertySet configProps;
private IServerObjectHelper serverObjectHelper;
private ServerLogger logger; private IRESTRequestHandler reqHandler;
public RestSOETest()
{
soe_name = this.GetType().Name;
logger =new ServerLogger();
reqHandler = new SoeRestImpl(soe_name, CreateRestSchema()) as IRESTRequestHandler;
}
#region IServerObjectExtension Members
public void Init(IServerObjectHelper pSOH)
{
serverObjectHelper = pSOH;
}
public void Shutdown()
{
}
#endregion
#region IObjectConstruct Members
public void Construct(IPropertySet props)
{
configProps = props;
}
#endregion
#region IRESTRequestHandler Members
public string GetSchema()
{
returnreqHandler.GetSchema();
}
public byte[] HandleRESTRequest(string Capabilities,string resourceName,string operationName, stringoperationInput,string outputFormat,stringrequestProperties,outstring responseProperties)
{
returnreqHandler.HandleRESTRequest(Capabilities, resourceName, operationName,operationInput, outputFormat, requestProperties,out responseProperties);
}
在構造函數中多了一個ServerLogger 的對象,通過名稱我們就可知道,該對象是一個日誌記錄對象,用該對象可以對我們的 SOE進行信息記錄,記錄後的信息,最後可以通過 Manager 的日誌查看。在構造函數中還調用了
CreateRestSchema 函數,如下:
private RestResource CreateRestSchema()
{
RestResource rootRes = new RestResource(soe_name, false,RootResHandler);
RestOperation sampleOper = new RestOperation("sampleOperation",newstring[] {"parm1","parm2" },
new string[] {"json" }, SampleOperHandler);
rootRes.operations.Add(sampleOper);
return rootRes;
}
在該函數中創建了Rest 資源和 Rest 資源的操作,並且資源和 Rest 操作都對應一個處理函數,我們一般稱作 Resthandler,這裏的資源和操作可能比較抽象,我們舉一個例子,比如說MapService 就是一個資源,而查詢就是一個操作,當我們執行操作的時候,處理整個邏輯的就是Resthandler,如上圖的
RootResHandler 和SampleOperHandler 分別是處理資源和資源操作的方法,這些 handler 的具體實現如下:
private byte[] RootResHandler(NameValueCollection boundVariables,string outputFormat,string requestProperties,outstring responseProperties)
{
responseProperties = null;
JsonObject result = new JsonObject();
result.AddString("hello", "world");
return Encoding.UTF8.GetBytes(result.ToJson());
}
private byte[] SampleOperHandler(NameValueCollectio boundVariables, JsonObject operationInput,
string outputFormat,string requestProperties, outstring responseProperties)
{
responseProperties = null;
string parm1Value;
bool found = operationInput.TryGetString("parm1",out parm1Value);
if (!found || string.IsNullOrEmpty(parm1Value))
throw newArgumentNullException("parm1");
string parm2Value;
found =operationInput.TryGetString("parm2",out parm2Value);
if (!found || string.IsNullOrEmpty(parm2Value))
throw newArgumentNullException("parm2");
JsonObject result = new JsonObject();
result.AddString("parm1", parm1Value);
result.AddString("parm2", parm2Value);
return Encoding.UTF8.GetBytes(result.ToJson());
}
在這裏我們要注意RestOperation類,該類對應了我們SOE的一個操作,該類的參數如下:
RestOperation (string name, string[]parameters, string[]supportedFormats, OperationHandlerhandler),這些參數分別對應了操作
的名稱,參數,支持的格式,以及該操作的處理函數。一個資源可以有子資源,並且一個資源可以對應多個操作,對於資源的handler我們可以不用關注,但是操作的handler是我們整個SOE的核心部分。下面是我們自定義的一個操作,其中pLineOperHandler是對應我們的handler
定義的操作:
RestOperation pLineOper = new RestOperation("pLineOperation",newstring[] {"RouteFieldName",
"RouteID", "Stationfrom","Stationto" },newstring[] {"json" },pLineOperHandler);
當定義好了RestOperation 之後,並且成功部署,那麼可以在服務目錄中看到下面的頁面:
JsonObject operationInput,
string outputFormat,
string requestProperties,
out string responseProperties)
{
responseProperties = "";
if (serverObjectHelper.ServerObject is IMapServer)
{
mapServer = (IMapServer3)serverObjectHelper.ServerObject;
}
// IMapServerObjects pMSO = serverObjectHelper.ServerObject as IMapServerObjects;
IMapServerDataAccess pMapServerDataAcc = null;
IFeatureClass pFeatureClass = null;
if (serverObjectHelper.ServerObject is IMapServerDataAccess)
{
pMapServerDataAcc = serverObjectHelper.ServerObject as IMapServerDataAccess;
pFeatureClass = pMapServerDataAcc.GetDataSource(mapServer.DefaultMapName, 0) as IFeatureClass;
}
// // IMapServer.DefaultMapName
//// IMap map = pMSO.get_Map(mapServer.DefaultMapName);
// //返回參與線性參考
// // routeFeatureLayer = (IFeatureLayer)map.get_Layer(0);
// //線性參考代碼
// IFeatureLayer featureLayer = routeFeatureLayer;
string _pPKName;
operationInput.TryGetString("RouteFieldName", out _pPKName);
if (_pPKName==null)
throw new ArgumentNullException("StationMeasure");
long? _pID;
operationInput.TryGetAsLong("RouteID", out _pID);
if (_pID == null)
throw new ArgumentNullException("RouteID");
double ? _pFrom;
operationInput.TryGetAsDouble("Stationfrom", out _pFrom);
if (_pFrom == null)
throw new ArgumentNullException("Stationfrom");
double? _pTo;
operationInput.TryGetAsDouble("Stationto", out _pTo);
if (_pTo == null)
throw new ArgumentNullException("Stationto");
IPolyline pointColl = FindRoutByMeasure(pFeatureClass, _pPKName.Substring(1, _pPKName.Length - 2), _pID.Value, _pFrom.Value, _pTo.Value);
JsonObject featureJson = new JsonObject();
featureJson.AddJsonObject("geometry", Conversion.ToJsonObject(pointColl as IGeometry));
return Encoding.UTF8.GetBytes( featureJson.ToJson());
}
{
IDataset pDataset = (IDataset)_pRouteFC;
IName pName = pDataset.FullName;
IRouteLocatorName pRouteLocatorName = new RouteMeasureLocatorNameClass();
pRouteLocatorName.RouteFeatureClassName = pName;
pRouteLocatorName.RouteIDFieldName = _pPKName;
pRouteLocatorName.RouteMeasureUnit = esriUnits.esriFeet;
pName = (IName)pRouteLocatorName;
IRouteLocator2 pRouteLocator = (IRouteLocator2)pName.Open();
IRouteLocation pRouteLoc = new RouteMeasureLineLocationClass();
pRouteLoc.MeasureUnit = esriUnits.esriFeet;
pRouteLoc.RouteID = _pID;
IRouteMeasureLineLocation rMLineLoc = (IRouteMeasureLineLocation)pRouteLoc;
rMLineLoc.FromMeasure = _pFrom;
rMLineLoc.ToMeasure = _pTo;
IGeometry pGeo = null;
esriLocatingError locError;
pRouteLocator.Locate(pRouteLoc, out pGeo, out locError);
return pGeo as IPolyline;
}
注意:
在這裏我將自己遇到的問題說一下,如果在ArcGIS 10或者之前的版本中使用過SOE,那麼發現下面的代碼是可以運行的,而且沒有問題:
IMapServerObjects3 pMSO = mapServer as IMapServerObjects3;
IMap map = pMSO.get_Map(mapServer.DefaultMapName);
但是在10.1的時候,這句代碼是不會成功的,錯誤的地方在IMapServerObjects3,這是因爲10.1中發佈的服務是使用MSD文檔,而IMapServerObjects3是針對MXD文檔的,因此在10.1中應避免,避免IMap,Ilayer等,那麼如何訪問要素類,柵格對象,表等對象呢?使用IMapServerDataAccess接口,該接口主要有兩個方法,如下圖: