Developers Knowledge Base

Learn how to manipulate, modify, and tune your GeoMedia WebMap, Geospatial Portal and Consumer portal instances.
Showing results for 
Search instead for 
Do you mean 

Implementing custom Backend searcher

by Technical Evangelist on ‎09-09-2015 04:10 AM - edited on ‎04-07-2017 08:00 AM by Technical Evangelist (720 Views)

Overview

By default the Consumer Portal layout of the Geospatial Portal product provides mechanisms to perform searches in Oracle DB and in the WMPS service.


This guide shows how to implement a plugin for Backend service that provides searching against a custom source.


This approach uses existing Backend service (that exposes REST API known by Consumer Portal) to drive the whole logic of search providers. If you want to consume an existing Web endpoint in Consumer Portal or in general not go through the Backend service use $GP.search.custom API to inject client-side custom searcher.

 

Prerequisites

You will need one of the following products: Geospatial Portal, Geomedia WebMap patched to version 2015 EP02 installed on a machine to have the Backend service running in a proper version.


In the SDK deliverable you can find CustomSearcher.zip that contains VS 2012 solution and all necessary dependent libraries. The solution is self contained for development. For deployment you will use installed Backend service (by default found in: C:\Program Files\Common Files\Hexagon\Services\AdminInstances\Backend)

 

Custom Searcher

The implementation of the custom search plugin boils down to:

 

  • authoring a new component which implements the ISearcher interface,
  • registering it in the Dependency Injection (DI) container,
  • configuring instance of the searcher in web.config,
  • and configuring Consumer Portal instance.

Implement ISearcher

The custom searcher component must implement ISearcher interface that describes a contract between SearchController and searcher instances.


New instances of the component are created at the service initialization time and reused for subsequent searches. Constructor parameters are provided directly from web.config file.


Search is executed by invoking ISearcher.PerformSearch(string query, PerformSearchParams performSearchParams) method on the component instance. query parameter is a query provided by a user. performSearchParams is an instance of PerformSearchParams class that defines additional properties to be used while performing the search and facilities to push back search results and detect search cancellation event.


PerformSearch(...) on the searcher instance is always invoked on a separate thread and search results queue is already thread-safe. This basically means that:

 

  • there is (usually) no need for spawning new threads and coordinating them when getting the results. You can invoke long running/blocking operations w/o additional burden.
  • if PerformSearch modifies searcher instance (object) state it must do so in a thread-safe way

A very simple custom searcher is presented here.

Where MyRecord class is defined as follows here.

 

Register in DI container

Once the custom searcher component is implemented. We need to register it in the DI container so that it is used in searches.


The DI container used in Backend service is Castle Windsor. You can find more information on using the container here


First part of the registration is done by defining IWindsorInstaller for the component we created:

    public class CustomSearcherInstaller: IWindsorInstaller
    {
        public void Install(IWindsorContainer container, IConfigurationStore store)
        {
            container.Register(
                Component.For<ISearcher>().ImplementedBy<CustomSearcher>().Named(SearcherSelector.GetSearcherComponentName("MyCustomSearcher")).LifeStyle.Transient
                );
        }
    }

What happens here may be described as follows:

 

  • Component.For<ISearcher>() - we are providing implementation of ISearcher service
  • .ImplementedBy<CustomSearcher>() - the implementation is defined in CustomSearcher class. Components created to satisfy the service will be CustomSearcher instances.
    • .Named(SearcherSelector.GetSearcherComponentName("MyCustomSearcher")) - the registration has a name attached (in our case: MyCustomSearcher). We use SearcherSelector.GetSearcherComponentName(string) helper method to acquire internal name of the component. More on searcher names can be found in Configuring instances - page doesn't exist ?
    • .LifeStyle.Transient - The component instances created by Windsor will have Transient life-cycle - they are managed by components that require them. Just leave it as-is Smiley Happy

Second part is letting know the main application to include the new IWindsorInstaller in container preparation routine. It is achieved by including the following change in web.config file (add lines starting with '+' character ommiting the character per se):


     <castle>
      <components/>
   +  <installers>
   +    <install type="CustomSearcher.CustomSearcherInstaller, CustomSearcher"/>
   +  </installers>
    </castle>
 

This will tell the application to load the assembly with the custom searcher into the AppDomain and use the CustomSearcherInstaller to register new searcher component.

 

Configure instance of the searcher in web.config

Having the component implemented and installed in the DI container we want to configure instances of the newly created searcher.


Each searcher may be instantiated multiple times with different parameters and each instance may be attached to a different dataset.


To define an instance of the searcher open web.config file and put additional line(s) in search/searchers section:


    <searchers>
      <oracleSearcher name="States" type="OracleSearcher" connectionString="..." objectNameField="NAME" objectTypeField="TYPE" centroidYField="LAT" centroidXField="LON" bboxY1Field="Y1" bboxX1Field="X1" bboxY2Field="Y2" bboxX2Field="X2" tableName="FC_USER.STATES" fieldsToSearchIn="NAME" dataset="45fd3e61-6cee-41bb-9062-b68edb08d09f" />
      <oracleSearcher name="Cities" type="OracleSearcher" connectionString="..." objectNameField="NAME" objectTypeField="TYPE" centroidYField="LAT" centroidXField="LON" bboxY1Field="Y1" bboxX1Field="X1" bboxY2Field="Y2" bboxX2Field="X2" tableName="FC_USER.CITIES" fieldsToSearchIn="NAME" dataset="8770f826-ec00-4b10-8174-b5fe2ed2f0b1" />
   +  <myCustomSearcher1 name="mcs1" type="MyCustomSearcher" dataset="db3d034f-bf19-4e0d-9f4f-891fd9254a6a" fileName="e:\temp\csvsearch.csv" />
    </searchers>
 

The tag name (myCustomSearcher1) and name attribute value may have arbitrary values. They can be used to modify the file in an automated manner (e.g. name attribute value can be used to present it to the user).


type attribute is what matches this config line with the newly created searcher. See to get an idea which name should be used here.


dataset attribute attaches the searcher to particular dataset defined ealier in the web.config file (see search/datasets section). Basically Consumer Portal invokes a search on a dataset and all searchers attached to it are invoked.


All additional attributes defined in the searcher instance element are passed to the constructor of the searcher component class (matching is done on "attribute name"-"parameter name" basis - order is not taken into account). All constructor parameters must be satisfied, however some may be resolved by the DI container (which is beyond the scope of this guide). Excessive attributes are ignored.

 

Configure Consumer Portal instance to use the custom searcher

Once all the changes in the Backend service are applied we need to make Consumer Portal use the custom searcher.


If the searcher was attached to the dataset that was already in use by Consumer Portal instance then no changes need to be made.


If it is not the case then there is a need to configure the search dataset in Consumer Portal instance. to achieve that open data\client_config.json file in the instance folder and put additional lines as follow here.

additionally replacing placeholders denoted by <...>:

 

  • <dataset_id> - dataset id as defined in the Backend service web.config file
  • <dataset_name> - dataset name that is displayed in the legend when search results are displayed
  • <hostname> - hostname as visible from the user machine (usually public name)
  • <search_name> - search source name displayed in advanced options of search panel
Overview