C# Plugins Developer Guide
C# Plugins Developer Guide
Note - this is an early preview of the plugins and might change very soon
Prerequisites
- .NET 5.0 Download
- Basic C# Knowledge
- Rider / Visual Studio / Visual Studio Code / any C# IDE
- Blast Nuget packages nuget.org, the package version aligns with Fluent Search version
- Fluent Search Version >= 0.9.21.0 Download
Getting Started
Fluent Search uses Search Applications
to search through many resources.
In this guide we will write a Search Application that converts numbers to Hex/Binary format.
Source Code
You can find an up-to-date code of the example below in my github.
Create new class library project
Open Powershell in any directory -
dotnet new classlib -n "NumberConverter.Fluent.Plugin"
NOTE - The plugin DLL has to end with the suffix Fluent.Plugin.dll
, if not Fluent Search will not try to load it.
Go to NumberConversionSearchApp directory and edit the NumberConversionSearchApp.csproj
to-
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net5.0-windows10.0.19041</TargetFramework>
</PropertyGroup>
</Project>
Add the nuget packages
In the Powershell run the commands -
cd NumberConverter.Fluent.Plugin
dotnet add package Blast.API --prerelease
dotnet restore
Implementation
You will need to add the following files to the NumberConverter.Fluent.Plugin
directory.
Create a search result
Each Search Application in Fluent Search returns ISearchResult
object that contains all the relevant information of the search result. (the left side of Fluent Search)
Add a new file called NumberConversionSearchResult.cs
with the following code -
using System.Collections.Generic;
using Blast.Core.Interfaces;
using Blast.Core.Objects;
using Blast.Core.Results;
namespace NumberConverter.Fluent.Plugin
{
public sealed class NumberConversionSearchResult : SearchResultBase
{
public NumberConversionSearchResult(int number, string searchAppName, string convertedNumber, string resultName, string searchedText,
string resultType, double score, IList<ISearchOperation> supportedOperations, ICollection<SearchTag> tags,
ProcessInfo processInfo = null) : base(searchAppName,
resultName, searchedText, resultType, score,
supportedOperations, tags, processInfo)
{
Number = number;
ConvertedNumber = convertedNumber;
// You can add Machine Learning features to improve search predictions
MlFeatures = new Dictionary<string, string>
{
["ConvertedNumber"] = ConvertedNumber
};
}
public int Number { get; }
public string ConvertedNumber { get; set; }
protected override void OnSelectedSearchResultChanged()
{
}
}
}
The Blast.API
gives the pre-implemented SearchResultBase
so you won't need to implement ISearchResult
.
Create the search operation
Every search results contains a list of ISearchOperation
(the right side of Fluent Search)
The user can select any operation to trigger it.
Add a new file called NumberConversionSearchOperation.cs
with the following code -
using Blast.Core.Results;
namespace NumberConverter.Fluent.Plugin
{
public enum ConversionType
{
Any,
Hex,
Binary
}
public class ConversionSearchOperation : SearchOperationBase
{
public ConversionType ConversionType { get; }
public static ConversionSearchOperation HexConversionSearchOperation { get; } =
new ConversionSearchOperation(ConversionType.Hex);
public static ConversionSearchOperation BinaryConversionSearchOperation { get; } =
new ConversionSearchOperation(ConversionType.Binary);
public ConversionSearchOperation(ConversionType conversionType) : base($"Convert more {conversionType} in web",
$"Opens a {conversionType} conversion website", "\uE8EF")
{
ConversionType = conversionType;
}
}
}
This is a basic implementation of the two supported operations - Hex / Binary.
We used static code to not create the same object each time.
Create the search application
You must add a search application, which is a class that implements ISearchApplication
.
Add a new file called NumberConversionSearchApp.cs
with the following code -
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
using Blast.API.Core.Processes;
using Blast.API.Processes;
using Blast.Core;
using Blast.Core.Interfaces;
using Blast.Core.Objects;
using Blast.Core.Results;
namespace NumberConverter.Fluent.Plugin
{
public class NumberConversionSearchApp : ISearchApplication
{
private const string SearchAppName = "NumberConvertor";
private readonly List<SearchTag> _searchTags;
private readonly SearchApplicationInfo _applicationInfo;
private readonly List<ISearchOperation> _supportedOperations;
public NumberConversionSearchApp()
{
// For icon glyphs look at https://docs.microsoft.com/en-us/windows/uwp/design/style/segoe-ui-symbol-font
_searchTags = new List<SearchTag>
{
new SearchTag
{Name = ConversionType.Hex.ToString(), IconGlyph = "\uE8EF", Description = "Convert to hex"},
new SearchTag
{Name = ConversionType.Binary.ToString(), IconGlyph = "\uE8EF", Description = "Convert to binary"}
};
_supportedOperations = new List<ISearchOperation>
{
ConversionSearchOperation.HexConversionSearchOperation,
ConversionSearchOperation.BinaryConversionSearchOperation
};
_applicationInfo = new SearchApplicationInfo(SearchAppName,
"This apps converts hex to decimal", _supportedOperations)
{
MinimumSearchLength = 1,
IsProcessSearchEnabled = false,
IsProcessSearchOffline = false,
ApplicationIconGlyph = "\uE8EF",
SearchAllTime = ApplicationSearchTime.Fast,
DefaultSearchTags = _searchTags
};
}
public ValueTask LoadSearchApplicationAsync()
{
// This is used if you need to load anything asynchronously on Fluent Search startup
return ValueTask.CompletedTask;
}
public SearchApplicationInfo GetApplicationInfo()
{
return _applicationInfo;
}
public async IAsyncEnumerable<ISearchResult> SearchAsync(SearchRequest searchRequest,
[EnumeratorCancellation] CancellationToken cancellationToken)
{
if (cancellationToken.IsCancellationRequested || searchRequest.SearchType == SearchType.SearchProcess)
yield break;
string searchedTag = searchRequest.SearchedTag;
string searchedText = searchRequest.SearchedText;
ConversionType conversionType = ConversionType.Any;
// Check that the search tag is something this app can handle
if (!string.IsNullOrWhiteSpace(searchedTag))
{
if (!searchedTag.Equals(SearchAppName, StringComparison.OrdinalIgnoreCase) &&
!Enum.TryParse(searchedTag, true, out conversionType))
yield break;
}
if (!int.TryParse(searchedText, out int number))
yield break;
if (conversionType == ConversionType.Any || conversionType == ConversionType.Hex)
{
string convertedNumber = number.ToString("X");
yield return new NumberConversionSearchResult(number, SearchAppName, convertedNumber,
$"Hex {searchedText} is {convertedNumber}", searchedText, "Hex", 2,
_supportedOperations, _searchTags);
}
if (conversionType == ConversionType.Any || conversionType == ConversionType.Binary)
{
string convertedNumber = Convert.ToString(number, 2);
yield return new NumberConversionSearchResult(number, SearchAppName, convertedNumber,
$"Binary {searchedText} is {convertedNumber}", searchedText, "Binary", 2,
_supportedOperations, _searchTags);
}
}
public ValueTask<ISearchResult> GetSearchResultForId(string serializedSearchObjectId)
{
// This is used to calculate a search result after Fluent Search has been restarted
// This is only used by the custom search tag feature
return new ValueTask<ISearchResult>();
}
public ValueTask<IHandleResult> HandleSearchResult(ISearchResult searchResult)
{
if (!(searchResult is NumberConversionSearchResult numberConversionSearchResult))
{
throw new InvalidCastException(nameof(NumberConversionSearchResult));
}
if (!(numberConversionSearchResult.SelectedOperation is ConversionSearchOperation conversionSearchOperation)
)
{
throw new InvalidCastException(nameof(ConversionSearchOperation));
}
// Get Fluent Search process manager instance
IProcessManager managerInstance = ProcessUtils.GetManagerInstance();
switch (conversionSearchOperation.ConversionType)
{
case ConversionType.Hex:
managerInstance.StartNewProcess(
$"https://www.hexadecimaldictionary.com/hexadecimal/{numberConversionSearchResult.Number:X}");
break;
case ConversionType.Binary:
managerInstance.StartNewProcess(
$"https://www.binary-code.org/binary/16bit/{Convert.ToString(numberConversionSearchResult.Number, 2)}");
break;
default:
throw new ArgumentOutOfRangeException();
}
return new ValueTask<IHandleResult>(new HandleResult(true, false));
}
}
}
This Search Application converts the searched text to hex/binary based on the searched tag.
For example if you receive -
Searched Text - "10"
Searched Tag - ""
The results will be "Hex 10 is A" and "Binary 10 is 1010".
And for -
Searched Text - "10"
Searched Tag - "hex"
The results will be only "Hex 10 is A".
Load the search app
Compile
First you should compile your plugin for release.
In the Powershell you opened eariler run -
dotnet publish -c Release -r win10-x64
or if you have any dependencies
dotnet publish -c Release -r win10-x64 --self-contained=true
And copy all the files (you can copy only your dlls, in this case it's NumberConversionSearchApp.dll
) from-
{YourDir}\NumberConversionSearchApp\bin\Release\net5.0-windows10.0.19041\win10-x64\publish
to -
If installed through Microsoft Store -
C:\Users\{your_user_name}\AppData\Local\Packages\21814BlastApps.BlastSearch_pdn8zwjh47aq4\LocalCache\Roaming\Blast\FluentSearchPlugins\NumberConversionSearchApp\
If installed through sideload -
C:\Users\{your_user_name}\AppData\Local\Packages\FluentSearch.SideLoad_4139t8dvwn2ka\LocalCache\Roaming\Blast\FluentSearchPlugins\NumberConversionSearchApp\
You will need to create these directories.
Plugins info file
In addition you will need to add a file called pluginsInfo.json
to your plugin directory, with the following information -
{
"IsEnabled": true,
"InstalledVersion": "1.0.0.0",
"Name": "NumberConverter",
"DisplayName": "Number Converter",
"Description": "Use hex/binary tags to convert numbers",
"PublisherName": "Blast Apps",
"Version": "1.0.0.0",
"URL": "https://github.com/adirh3/NumberConverter.Fluent.Plugin/",
"IconGlyph": "\uE8EF"
}
You can find icon glyphs here.
Check Fluent Search
Restart Fluent Search and check if your search application is working!
Troubleshooting
If the Search Application does not load, please check for logs in the plugin directory, in this case -
..\FluentSearchPlugins\NumberConversionSearchApp
Usually a plugin will fail to load when one or more of it dependencies are missing, so make sure you copy all the relevant DLLs to the plugin directory.
For help please send a mail to support@fluentsearch.net