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:
TypeNameis the assembly-qualified name,Namespace.Type, Assembly, loaded when the database opens. An emptyTypeNameorRelatudeServicesmeans the hosted service, except inAISettings, where empty means Azure OpenAI.- A public constructor takes the settings:
AIProviderSettings,ImagingProviderSettings,FileToTextProviderSettings,TranslationProviderSettings,IPLookupProviderSettingsorSMSProviderSettings. Your class getsServiceUrl,ApiKeyand the rest from the same settings, and the same settings page, as the built-in providers. Keep the key in theRelatudeDBconfiguration 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 throwNotSupportedExceptionby default. AnIImagingProviderthrows it from operations it does not support and leaves them out ofGetOperationsAsync. LeaveCreditsandCreditsLeftat 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
NodeStoreconstructor:new NodeStore(datastore, sms: new MyGatewaySmsProvider(settings)). The other parameters areimaging,fileToText,translationandipLookup.