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. Check out the software requirements for compatible version numbers.
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, use the Browse button.
- Select Trisoft.InfoShare.Plugins.SDK.dll, then Add.
- To be able to view the code documentation of the Trisoft.InfoShare.Plugins.SDK.dll, also copy Trisoft.InfoShare.Plugins.SDK.xml.
- Add a reference to a plugin common helper (Trisoft.InfoShare.Plugins.Common.dll). For example, you can copy the file from \Applications\Plugins\Trisoft.InfoShare.Plugins.Common.dll.
- Browse to the project, then right-click References, and select Add Reference.
- To select the reference you want to add, use the Browse button.
- Select Trisoft.InfoShare.Plugins.Common.dll, then Add.
- To be able to view the code documentation of the Trisoft.InfoShare.Plugins.Common.dll, also copy Trisoft.InfoShare.Plugins.Common.xml.
- 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