Creating a search extension handler in C#
This example shows how to create a custom search extension handler to connect the metadata fields to an external metadata source
Before you begin
Important: The information and the procedure herein are provided as is without warranty of any kind, either express or implied.
The following products need to be already installed on your machine:
- Microsoft .NET FrameWork
- Microsoft Visual Studio
Procedure
- Create a Visual Studio Project. In this example, the project is called
MyCustomSearchExtensionLibrary, and its type is Class Library. - Add a reference to a plugin SDK (Trisoft.InfoShare.Plugins.SDK.dll). For example, you can copy the file from \Applications\Common\Trisoft.InfoShare.Plugins.SDK.dll.
- Browse to the project, then right-click References, and select Add Reference.
- To select the reference you want to add, click the Browse button.
- Select Trisoft.InfoShare.Plugins.SDK.dll, and click Add.
- Add a reference to the System.ComponentModel.Composition assembly.
- Add a reference to the System.Xml assembly.
- Create a new MyCustomSearchExtensionHandler class.
- The name of the handler corresponds to the value assigned to ExportAttribute, and it needs to be unique.
- The LogService on IQueryEnhanceHandlerConfiguration manages all log entries as part of the standard log chaining, as configured in NLog.config. If you want to create a separate logging chain, you need to set up a new Logger
using System; using System.Collections.Generic; using System.ComponentModel.Composition; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Xml.Linq; using System.Xml.XPath; using Trisoft.InfoShare.Plugins.SDK; using Trisoft.InfoShare.Plugins.SDK.Extensions.Search; namespace MyCustomSearchExtensionLibrary { /// <summary> /// Custom search extension handler that adds an additional full text search clause with the corresponding labels /// if there are certain term ids found as values for the configured field in the users submitted search query /// The full search text clause is added by adding an extra "or" between the original field and a new ISHANYWHERE field clause (full text search field) /// when the field operator is not provided or is "equal" or is "contains". /// </summary> // This attribute is used to make the class discoverable by InfoShare. [Export("MyCustomSearchExtensionHandler", typeof(IQueryEnhanceHandler))] [PartCreationPolicy(CreationPolicy.NonShared)] public class MyCustomSearchExtensionHandler : IQueryEnhanceHandler { /// <summary> /// Field element name of the CONTINENTS field /// </summary> private string _continentsFieldName; /// <summary> /// Field level of the CONTINENTS field /// </summary> private string _continentsFieldLevel; /// <summary> /// Set to true when all the necessary configuration parameters are present. /// </summary> private bool _mustTryToEnhanceQuery = false; /// <summary> /// This method will be called by the business code after the instance of the handler is created. /// </summary> /// <param name="configuration">A <see cref="IQueryEnhanceHandlerConfiguration"/> containing the query enhance configuration.</param> public void Initialize(IQueryEnhanceHandlerConfiguration configuration) { if (configuration.Parameters.TryGetValue("continentsfieldname", out _continentsFieldName) && configuration.Parameters.TryGetValue("continentsfieldlevel", out _continentsFieldLevel)) { _mustTryToEnhanceQuery = true; // You could also throw an exception here } } /// <summary> /// This method can be used to enhance the xml query /// </summary> /// <param name="context">The arguments of the method containing the xml query to enhance.</param> /// <returns>The result with the enhanced xml query.</returns> public IEnhanceQueryResult EnhanceQuery(IEnhanceQueryContext context) { if (_mustTryToEnhanceQuery) { var continentQueryElements = context.Query.XPathSelectElements(String.Format("ishquery//ishfield[@name='{0}'][@level='{1}'][text()]", _continentsFieldName, _continentsFieldLevel)).ToList(); if (continentQueryElements.Any()) { foreach (var continentQueryElement in continentQueryElements) { if (continentQueryElement.Attribute("ishoperator") == null || continentQueryElement.Attribute("ishoperator").Value == "equal" || continentQueryElement.Attribute("ishoperator").Value == "contains") { var continentIds = new List<string>(continentQueryElement.Value.Split(new string[] {", "}, StringSplitOptions.None)); var continents = new List<string>(); // For all the ids that we passed, we try to resolve it into a tag foreach (string id in continentIds) { switch (id) { case "SOA": continents.Add(@"""South America"""); break; case "NOA": continents.Add(@"""North America"""); break; case "AFR": continents.Add(@"""Africa"""); break; case "EUR": continents.Add(@"""Europe"""); break; case "ASA": continents.Add(@"""Asia"""); break; case "AUS": continents.Add(@"""Australia"""); break; case "OCE": continents.Add(@"""Oceania"""); break; case "ANT": continents.Add(@"""Antarctica"""); break; default: // If id does not match - simply skip it break; } } if (continents.Any()) { // We will replace the field with (field OR ISHANYWHERE), so if the users query would contain // <ishfield name="FTESTCONTINENTS" level="logical" ishoperator="equal">OCE, AFR, ANT</ishfield> // it is enhanced to // <or> // <ishfield name="FTESTCONTINENTS" level="logical" ishoperator="equal">OCE, AFR, ANT</ishfield> // <ishfield name="ISHANYWHERE" level="none" ishoperator="contains">"Oceania", "Africa", "Antarctica"</ishfield> // </or> var anywhereField = new XElement("ishfield", new XAttribute("name", "ISHANYWHERE"), new XAttribute("level", "none"), new XAttribute("ishoperator", "contains"), String.Join(", ", continents)); continentQueryElement.ReplaceWith( new XElement("or", continentQueryElement, anywhereField)); } } } } } // Always return a query, either the original one or an enhanced one return new EnhanceQueryResult() { Query = context.Query }; } /// <summary> /// Explicitly release any disposable resources /// </summary> public void Dispose() { // In our example we don't need a cleanup } } /// <summary> /// Simplistic and minimal implementation of the <code>EnhanceQueryResult</code> interface. /// </summary> public class EnhanceQueryResult : IEnhanceQueryResult { /// <summary> /// Enhanced xml query /// </summary> public XDocument Query { get; set; } } } - Deploy the new handler.
- Configure the new handler.
<infoShareExtensionConfig version='1.0'> <search> <queryenhance sourceref="MyCustomSearchEnhancer" /> </search> <sources> <source id='MyCustomSearchEnhancer' handler='MyCustomSearchExtensionHandler'> <initialize> <parameters> <parameter name='continentsfieldname'>FCONTINENTS</parameter> <parameter name='continentsfieldlevel'>logical</parameter> </parameters> </initialize> </source> </sources> </infoShareExtensionConfig>
Related tasks