Configure Jinaga

Your Jinaga configuration provides these essential pieces of information:

  • Logging configuration
  • The URL of the replicator
  • The authentication provider
  • Authorization and distribution rules
  • The storage mechanism

Start simple and expand as you build more features.

JinagaConfig

Create a class to hold your Jinaga configuration. Use JinagaClient.Create to initialize a client having an in-memory store.

public static class JinagaConfig
{
    public static JinagaClient CreateJinagaClient(IServiceProvider services)
    {
        return JinagaClient.Create(opt =>
        {
            // Configuration options will go here
        });
    }
}

Register the client in MauiProgram. Add the following line to the CreateMauiApp method.

builder.Services.AddSingleton(JinagaConfig.CreateJinagaClient);

This initial configuration will you get started. Use the following options to add features as you need them.

Capture Logs

The Jinaga client can log messages to your provided logger. Set the LoggerFactory property to an ILoggerFactory implementation that you have configured.

return JinagaClient.Create(opt =>
{
    opt.LoggerFactory = services.GetRequiredService<ILoggerFactory>();
});

Connect to a Replicator

A replicator is your application backend. It stores the facts and distributes them to other clients. Set the HttpEndpoint property to the URL of the replicator.

return JinagaClient.Create(opt =>
{
    var settings = new Settings();
    opt.HttpEndpoint = new Uri(settings.ReplicatorUrl);
});

Be sure to register an HTTP client factory in MauiProgram.

builder.Services.AddHttpClient();

Authenticate

Your mobile app users will likely have either a Google or Apple account. Allow them to log into your app using their existing credentials. The replicator in Azure has built-in support for Google and Apple authentication. Set the HttpAuthenticationProvider to a class that implements IHttpAuthenticationProvider.

return JinagaClient.Create(opt =>
{
    opt.HttpAuthenticationProvider = services.GetRequiredService<IHttpAuthenticationProvider>();
});

The Jinaga.Maui package includes an implementation that authenticates a Jinaga replicator using Google or Apple. Create settings for the authentication provider in your JinagaConfig class.

public static AuthenticationSettings CreateAuthenticationSettings(IServiceProvider services)
{
    var settings = new Settings();

    var authUrlByProvider = ImmutableDictionary<string, string>.Empty;
    authUrlByProvider = authUrlByProvider.Add("Apple", settings.AppleAuthUrl);
    authUrlByProvider = authUrlByProvider.Add("Google", settings.GoogleAuthUrl);

    var authenticationSettings = new AuthenticationSettings(
        authUrlByProvider,
        settings.AccessTokenUrl,
        settings.RevokeUrl,
        settings.CallbackUrl,
        settings.ClientId,
        settings.Scope,
        UpdateUserName);
    return authenticationSettings;
}

private static async Task UpdateUserName(JinagaClient jinagaClient, User user, UserProfile profile)
{
    // Called when the user logs in so that the app can record the user's name.
}

Register these components in MauiProgram.

    builder.Services.AddSingleton(JinagaConfig.CreateAuthenticationSettings);
    builder.Services.AddSingleton(WebAuthenticator.Default);
    builder.Services.AddJinagaAuthentication();

To initiate login, call the Login method on IAuthenticationService. Pass the name of the provider to use. This is typically done in an application view model.

public partial class AppShellViewModel : ObservableObject
{
    private readonly IAuthenticationService authenticationService;
    private readonly UserProvider userProvider;

    public ICommand LogIn { get; }
    public ICommand LogOut { get; }

    public AppShellViewModel(IAuthenticationService authenticationService, UserProvider userProvider)
    {
        LogIn = new AsyncRelayCommand<string>(HandleLogIn);
        LogOut = new AsyncRelayCommand(HandleLogOut);

        this.authenticationService = authenticationService;
        this.userProvider = userProvider;
    }

    private async Task HandleLogIn(string? provider)
    {
        var isLoggedIn = await authenticationService.LogIn(provider ?? "Apple");

        if (isLoggedIn)
        {
            // Use two slashes to prevent back navigation.
            await Shell.Current.GoToAsync("//loggedin");
        }
    }

    public async Task HandleLogOut()
    {
        await authenticationService.LogOut();

        await Shell.Current.GoToAsync("//notloggedin");
    }
}

Authorization and Distribution Rules

Authorization rules determine who can create facts. Distribution rules determine who can read them. They are covered in Define Authorization Rules and Define Distribution Rules.

Local Storage

The Jinaga.Store.SQLite package provides local storage for offline operation. To use it, change JinagaClient.Create to JinagaSQLiteClient.Create and set the SQLitePath property. All other options remain the same.

return JinagaSQLiteClient.Create(opt =>
{
    opt.SQLitePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "myapp.db");
});

Continue With

Define a Model

Jinaga is a product of Jinaga LLC.

Michael L Perry, President