ARCGIS 10.1 for Server SOE介紹及開發實例(2)

第二章 SOE使用
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 之後,並且成功部署,那麼可以在服務目錄中看到下面的頁面: 

我們可以看出,RestOperation 類中的參數和這個對應,當我們點了 GET 或者 POST 操作之後,這個時候就執行 PlineOperHandler 操作,該函數的定義如下:
private byte[] pLineOperHandler(NameValueCollection boundVariables,
                                                                       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());
   }
在前面已經介紹過,SOE裏面的很大一部分代碼是和AO對象打交道,而這部分也是我們的核心功能,當我們使用Esri提供給的SOE模板之後,我們要核心要做的就是寫SOE請求函數,在這個請求函數也就是handler中,我們的核心AO代碼就在這裏,我這個函數的核心代碼如下:
        IPolyline FindRoutByMeasure(IFeatureClass _pRouteFC, string _pPKName, object _pID, double _pFrom,                                                                                                                                                                    double _pTo)
            {
                  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 Engine中做過和線性參考相關的工作,那麼這端代碼是完全可以在ArcGIS Engine中使用的,所以說SOE的開發並不是想象中的困難,相反如果有了AO基礎的話,的確是很簡單。
注意:
在這裏我將自己遇到的問題說一下,如果在ArcGIS 10或者之前的版本中使用過SOE,那麼發現下面的代碼是可以運行的,而且沒有問題:
                IMapServer mapServer = (IMapServer3)serverObjectHelper.ServerObject;
                  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接口,該接口主要有兩個方法,如下圖:


第一個方法主要獲取表,要素類,柵格數據,但是在地圖文檔中我們有的數據是和其他數據有關聯的的比如join操作,那麼通過第二個方法我們不但可以獲取源表的數據,還可以獲取目的表的數據。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章