Introduction
Message descriptions can be stored in IMessageDescriptions tables (Avalanche.Message.dll).
public class DatabaseMessages : MessageDescriptions
{
/// <summary>Singleton</summary>
static readonly Lazy<DatabaseMessages> instance = new Lazy<DatabaseMessages>(() => new DatabaseMessages().SetAllReadOnly().SetReadOnly());
/// <summary>Singleton</summary>
public static DatabaseMessages Instance => instance.Value;
/// <summary>Exception factory for http errors</summary>
static readonly Func<IMessage, Exception> httpExceptionFactory = (IMessage m) => new HttpRequestException(m.Print(), m.Error, (System.Net.HttpStatusCode)m.HttpStatusCode());
/// <summary>Initialize fields</summary>
public DatabaseMessages() : base() { this.AddRange(MessageDescriptionsExtensions.FieldReader(this)); }
/// <summary></summary>
public readonly IMessageDescription ChannelNotFound = Http(nameof(ChannelNotFound), "Channel {channelId} is not found", HttpStatusCode.NotFound);
/// <summary>User is not authenticated (logged in)</summary>
public readonly IMessageDescription UserNotAuthenticated = Http(nameof(UserNotAuthenticated), "User is not authenticated", HttpStatusCode.Forbidden);
/// <summary>User is not (email) verified</summary>
public readonly IMessageDescription UserNotConfirmedEmail = Http(nameof(UserNotConfirmedEmail), "User's {user} e-mail is not verified", HttpStatusCode.Forbidden);
/// <summary>User not found in database</summary>
public readonly IMessageDescription UserNotFound = Http(nameof(UserNotFound), "User {user} is not found", HttpStatusCode.NotFound);
/// <summary>User is not subscribed on channel</summary>
public readonly IMessageDescription UserNotSubscribed = Http(nameof(UserNotSubscribed), "User {user} is not subscribed on channel {channel}", HttpStatusCode.Forbidden);
/// <summary>Create http message</summary>
public static IMessageDescription Http(string key, string template, HttpStatusCode? httpCode)
{
// Create description
MessageDescription messageDescription = new MessageDescription(key, null, TemplateFormat.BraceAlphaNumeric.Text[template])
.SetCode(new FNVHash32().HashIn(key))
.SetHttpStatusCode(httpCode)
.SetException(httpExceptionFactory);
// Error
if (httpCode.HasValue && (int)httpCode.Value >= 300) messageDescription.SetHResult(0x80000000).SetSeverity(MessageLevel.Error);
// Ok
else messageDescription.SetHResult(0x00000000).SetSeverity(MessageLevel.Information);
// Return
return messageDescription;
}
}
Tables can be added to dependency injection (Read more).
// Service collection
IServiceCollection serviceCollection = new ServiceCollection()
.AddSingleton<ILocalization>(Localization.Default)
.AddSingleton<DatabaseMessages>(sp => new DatabaseMessages().LocalizeMessages(sp.GetRequiredService<ILocalization>()));
// Service provider
using var service = serviceCollection.BuildServiceProvider();
// Get messages
DatabaseMessages messages = service.GetRequiredService<DatabaseMessages>();
// Create message
IMessage status = messages.ChannelNotFound.New("00000000-0000-0000-1000-000000000000");
// Print message
WriteLine(status.Print());
.ToYamlText(), .ToYamlNode() and .ToYamlFile() prints tables as localization template file (Avalanche.Message.Localization.dll) (Read more). Translations to other languages can be written on the constructed template file.
// Service collection
IServiceCollection serviceCollection = new ServiceCollection()
.AddSingleton<ILocalization>(Localization.Default)
.AddSingleton<DatabaseMessages>(sp => new DatabaseMessages().LocalizeMessages(sp.GetRequiredService<ILocalization>()));
// Service provider
using var services = serviceCollection.BuildServiceProvider();
// Get all message description tables in dependency injection
IEnumerable<IMessageDescriptions> list = serviceCollection
.Where(sd => sd.ServiceType.IsAssignableTo(typeof(IMessageDescriptions)))
.Select(sd => (IMessageDescriptions)services.GetService(sd.ServiceType)!);
// Print all tables
WriteLine(list.ToYamlText());
// Print one table
WriteLine(list.First().ToYamlText());
.WriteYamlFiles(dir) writes templates for each message description.
// Print localization template.l.yaml when running from IDE in Debug
if (Debugger.IsAttached && MessageDescriptionsTemplateExtensions.TryGetSourcePath(out string sourcePath) && Path.Exists(sourcePath))
{
// Write to file
serviceCollection // 'builder.Services' in Asp.Net
.Where(sd => sd.ServiceType.IsAssignableTo(typeof(IMessageDescriptions)))
.Select(sd => (IMessageDescriptions)services.GetService(sd.ServiceType)!) // 'app.Services' in Asp.Net
.WriteYamlFiles(sourcePath);
}
DatabaseMessages:
Culture: ''
TemplateFormat: BraceAlphaNumeric
Items:
- Key: ChannelNotFound
Text: Channel {channelId} is not found
- Key: UserNotFound
Text: User {user} is not found
- Key: UserNotConfirmedEmail
Text: User's {user} e-mail is not verified
- Key: UserNotAuthenticated
Text: User is not authenticated
- Key: UserNotSubscribed
Text: User {user} is not subscribed on channel {channel}
The following snippet creates a .template.l.yaml when running from IDE in Debug mode. Template can be maintained in source control.
// Print localization template.l.yaml when running from IDE in Debug
if (Debugger.IsAttached && MessageDescriptionsTemplateExtensions.TryGetSourcePath(out string sourcePath) && Path.Exists(sourcePath))
{
// Write to file
serviceCollection // 'builder.Services' in Asp.Net
.Where(sd => sd.ServiceType.IsAssignableTo(typeof(IMessageDescriptions)))
.Select(sd => (IMessageDescriptions)services.GetService(sd.ServiceType)!) // 'app.Services' in Asp.Net
.WriteYamlFiles(sourcePath);
}
Full Example
Full example
using System.Diagnostics;
using System.Globalization;
using System.Net;
using Avalanche.Localization;
using Avalanche.Message;
using Avalanche.Template;
using Avalanche.Utilities;
using Microsoft.Extensions.DependencyInjection;
using static System.Console;
public class printtemplate
{
public static void Run()
{
{
// <01>
// Service collection
IServiceCollection serviceCollection = new ServiceCollection()
.AddSingleton<ILocalization>(Localization.Default)
.AddSingleton<DatabaseMessages>(sp => new DatabaseMessages().LocalizeMessages(sp.GetRequiredService<ILocalization>()));
// Service provider
using var service = serviceCollection.BuildServiceProvider();
// Get messages
DatabaseMessages messages = service.GetRequiredService<DatabaseMessages>();
// Create message
IMessage status = messages.ChannelNotFound.New("00000000-0000-0000-1000-000000000000");
// Print message
WriteLine(status.Print());
// </01>
}
{
// <11>
// Service collection
IServiceCollection serviceCollection = new ServiceCollection()
.AddSingleton<ILocalization>(Localization.Default)
.AddSingleton<DatabaseMessages>(sp => new DatabaseMessages().LocalizeMessages(sp.GetRequiredService<ILocalization>()));
// Service provider
using var services = serviceCollection.BuildServiceProvider();
// Get all message description tables in dependency injection
IEnumerable<IMessageDescriptions> list = serviceCollection
.Where(sd => sd.ServiceType.IsAssignableTo(typeof(IMessageDescriptions)))
.Select(sd => (IMessageDescriptions)services.GetService(sd.ServiceType)!);
// Print all tables
WriteLine(list.ToYamlText());
// Print one table
WriteLine(list.First().ToYamlText());
// </11>
// <14>
// Print localization template.l.yaml when running from IDE in Debug
if (Debugger.IsAttached && MessageDescriptionsTemplateExtensions.TryGetSourcePath(out string sourcePath) && Path.Exists(sourcePath))
{
// Write to file
serviceCollection // 'builder.Services' in Asp.Net
.Where(sd => sd.ServiceType.IsAssignableTo(typeof(IMessageDescriptions)))
.Select(sd => (IMessageDescriptions)services.GetService(sd.ServiceType)!) // 'app.Services' in Asp.Net
.WriteYamlFiles(sourcePath);
}
// </14>
}
}
// <100>
public class DatabaseMessages : MessageDescriptions
{
/// <summary>Singleton</summary>
static readonly Lazy<DatabaseMessages> instance = new Lazy<DatabaseMessages>(() => new DatabaseMessages().SetAllReadOnly().SetReadOnly());
/// <summary>Singleton</summary>
public static DatabaseMessages Instance => instance.Value;
/// <summary>Exception factory for http errors</summary>
static readonly Func<IMessage, Exception> httpExceptionFactory = (IMessage m) => new HttpRequestException(m.Print(), m.Error, (System.Net.HttpStatusCode)m.HttpStatusCode());
/// <summary>Initialize fields</summary>
public DatabaseMessages() : base() { this.AddRange(MessageDescriptionsExtensions.FieldReader(this)); }
/// <summary></summary>
public readonly IMessageDescription ChannelNotFound = Http(nameof(ChannelNotFound), "Channel {channelId} is not found", HttpStatusCode.NotFound);
/// <summary>User is not authenticated (logged in)</summary>
public readonly IMessageDescription UserNotAuthenticated = Http(nameof(UserNotAuthenticated), "User is not authenticated", HttpStatusCode.Forbidden);
/// <summary>User is not (email) verified</summary>
public readonly IMessageDescription UserNotConfirmedEmail = Http(nameof(UserNotConfirmedEmail), "User's {user} e-mail is not verified", HttpStatusCode.Forbidden);
/// <summary>User not found in database</summary>
public readonly IMessageDescription UserNotFound = Http(nameof(UserNotFound), "User {user} is not found", HttpStatusCode.NotFound);
/// <summary>User is not subscribed on channel</summary>
public readonly IMessageDescription UserNotSubscribed = Http(nameof(UserNotSubscribed), "User {user} is not subscribed on channel {channel}", HttpStatusCode.Forbidden);
/// <summary>Create http message</summary>
public static IMessageDescription Http(string key, string template, HttpStatusCode? httpCode)
{
// Create description
MessageDescription messageDescription = new MessageDescription(key, null, TemplateFormat.BraceAlphaNumeric.Text[template])
.SetCode(new FNVHash32().HashIn(key))
.SetHttpStatusCode(httpCode)
.SetException(httpExceptionFactory);
// Error
if (httpCode.HasValue && (int)httpCode.Value >= 300) messageDescription.SetHResult(0x80000000).SetSeverity(MessageLevel.Error);
// Ok
else messageDescription.SetHResult(0x00000000).SetSeverity(MessageLevel.Information);
// Return
return messageDescription;
}
}
// </100>
}