Relatude Help

35.2 A provider of your own

Implement the service's interface and name your class in the database's settings. A text message gateway of your own, as an example:

using System.Net.Http.Json;
using Relatude.DB.SMS;

namespace MyApp.Messaging;

public sealed class MyGatewaySmsProvider(SMSProviderSettings settings) : ISMSProvider {
    readonly HttpClient _http = new();

    public string Name => "My gateway";

    public async Task<SmsReceipt> SendAsync(string to, string message, string? from = null,
        string? reference = null, CancellationToken cancellationToken = default) {
        using var request = new HttpRequestMessage(HttpMethod.Post, settings.ServiceUrl) {
            Content = JsonContent.Create(new { to, text = message, from = from ?? settings.From }),
        };
        request.Headers.Add("Authorization", "Bearer " + settings.ApiKey);
        using var response = await _http.SendAsync(request, cancellationToken);
        response.EnsureSuccessStatusCode();
        var messageId = await response.Content.ReadAsStringAsync(cancellationToken);
        return new SmsReceipt(messageId, to, Parts: 1, Credits: 0, CreditsLeft: 0, reference);
    }

    public Task<SmsQuote> QuoteAsync(string to, string message, CancellationToken cancellationToken = default)
        => Task.FromResult(new SmsQuote(to, Parts: 1, Credits: 0, Unicode: false, Characters: message.Length));

    public void Dispose() => _http.Dispose();
}
{
  // one database in ContainerSettings, in relatude.db.json
  "SMSSettings": {
    "TypeName": "MyApp.Messaging.MyGatewaySmsProvider, MyApp",
    "ServiceUrl": "https://sms.example.com/send",
    "From": "MyShop"
    // ApiKey: in the RelatudeDB configuration section, not in this file
  }
}

The same rules apply to every service:

  • TypeName is the assembly-qualified name, Namespace.Type, Assembly, loaded when the database opens. An empty TypeName or RelatudeServices means the hosted service, except in AISettings, where empty means Azure OpenAI.
  • A public constructor takes the settings: AIProviderSettings, ImagingProviderSettings, FileToTextProviderSettings, TranslationProviderSettings, IPLookupProviderSettings or SMSProviderSettings. Your class gets ServiceUrl, ApiKey and the rest from the same settings, and the same settings page, as the built-in providers. Keep the key in the RelatudeDB configuration section (§12.2).
  • One instance serves the whole database. It is created when the database opens, so a type that cannot be created stops the open with the reason. It must be thread-safe, and it is disposed when the database closes.
  • Implement only what you offer. ISMSProvider's batch methods throw NotSupportedException by default. An IImagingProvider throws it from operations it does not support and leaves them out of GetOperationsAsync. Leave Credits and CreditsLeft at 0.
  • Answers are cached for your own imaging, file-to-text and translation providers too (§34.5).
  • A store built from code gets the provider in the NodeStore constructor: new NodeStore(datastore, sms: new MyGatewaySmsProvider(settings)). The other parameters are imaging, fileToText, translation and ipLookup.