Skip to main content

Lagoon Console Applications

A Lagoon Batch application is a .NET console application that starts with LagoonConsoleApplication.Run<Main>(args). It uses Lagoon.Console, which wraps McMaster.Extensions.CommandLineUtils, to declare command-line commands.

In the demo application, the Batch project references the model, the services, and the commands. The Main class inherits from LgApplication<ApplicationDbContext>: it is not a web host, but a console entry point capable of configuring the DbContext, dependency injection, and subcommands.

See also the architecture of a Lagoon solution.

Entry point​

The Program.cs file remains deliberately short. It passes the command-line arguments to the Lagoon framework.

Program.cs
namespace Demo.Batch;

/// <summary>
/// The entry point of the application.
/// </summary>
internal class Program
{
/// <summary>
/// Application startup.
/// </summary>
/// <param name="args">The arguments.</param>
public static int Main(string[] args)
{
// Démarre l'application console Lagoon et retourne le code de sortie.
return LagoonConsoleApplication.Run<Main>(args);
}
}
ItemRole
LagoonConsoleApplication.Run<Main>(args)Initializes and runs the Lagoon console application.
MainHolds the application configuration and the list of subcommands.
argsContains the arguments passed from the command line.
intRepresents the process exit code.

The Main class​

The Main class configures the console application and declares the available commands with [Subcommand]. In the demo, UpdateDbCommand is enabled, while BatchCommand is present as an example to enable.

Main.cs
using Lagoon.Console.Application;
using Microsoft.EntityFrameworkCore;

namespace Demo.Batch;

/// <summary>
/// The console application's configuration and event manager.
/// </summary>
[Subcommand(typeof(UpdateDbCommand))]
// [Subcommand(typeof(BatchCommand))] <-- À décommenter pour activer la commande "batch".
public class Main : LgApplication<ApplicationDbContext>
{
/// <summary>
/// New instance handeling the Pierre-Fabre shared configuration.
/// </summary>
public Main() : base() { }

/// <summary>
/// Called when a main application DbContext need to be configured.
/// </summary>
/// <param name="builder">A builder used to create or modify options for the main database context.</param>
protected override void OnConfigureDbContext(DbContextOptionsBuilder builder)
{
// Réutilise la configuration du modèle pour cibler la bonne base de données.
ApplicationDbContext.Configure(builder, Configuration, ApplicationInformation.IsDevelopment);
}

/// <summary>
/// Register the services for the application.
/// </summary>
/// <param name="services">The service collection.</param>
protected override void OnConfigureServices(IServiceCollection services)
{
// Enregistre les services applicatifs disponibles pour les commandes.
Services.Registry.RegisterServices(services);
}

/// <summary>
/// Show the status of the application's resources.
/// </summary>
protected override Task OnShowStatusAsync(ShowStatusEventArgs e)
{
// Ajouter ici les contrôles de statut spécifiques à l'application.
return Task.CompletedTask;
}
}

Responsibilities of Main​

ResponsibilityMethod or attribute
Start the known commands[Subcommand(typeof(...))]
Configure EF CoreOnConfigureDbContext(DbContextOptionsBuilder builder)
Register the business servicesOnConfigureServices(IServiceCollection services)
Complete the status displayOnShowStatusAsync(ShowStatusEventArgs e)

Declaring a command​

A command is a class decorated with [Command]. Its options are exposed by properties decorated with [Option]. Its execution is carried out by an OnExecute or OnExecuteAsync method.

The following example reproduces the pattern found in BatchCommand.cs.

BatchCommand.cs
namespace Demo.Batch.Commands;

/// <summary>
/// Execute the batch actions.
/// </summary>
[Command(Name = "batch", Description = "Batch actions.")]
public class BatchCommand
{
/// <summary>
/// Indicate if the batch must include the foo import.
/// </summary>
[Option("--import-foo", "Import the ...", CommandOptionType.NoValue)]
public bool ImportFooEnabled { get; set; }

/// <summary>
/// Execute the specified batch actions.
/// </summary>
/// <param name="app">The main application.</param>
/// <param name="fooService">The injected service that performs the foo import.</param>
public void OnExecute(Main app, MyFooService fooService)
{
// Affiche la version de l'application au début du traitement.
app.ShowVersion();

if (ImportFooEnabled)
{
// Le service est injecté automatiquement depuis les paramètres de méthode.
fooService.ImportFoo();
}

Console.WriteLine("Batch successfuly done !");
}
}

Injecting services in OnExecute​

Lagoon follows the McMaster pattern: services are not injected by constructor in the command. They are resolved from the parameters of OnExecute or OnExecuteAsync.

ParameterOrigin
Main appInstance of the Lagoon console application.
MyFooService fooServiceService registered in OnConfigureServices.

The demo's _Usings.cs file notably exposes the namespaces needed by the commands: Lagoon.Console.Application, Lagoon.Console.Commands, McMaster.Extensions.CommandLineUtils, and Microsoft.Extensions.DependencyInjection.

Running a command​

Once the command is added to Main with [Subcommand(typeof(BatchCommand))], it becomes accessible from the Batch executable.

Demo.Batch batch --import-foo

Points to note​

Commands and database

The Batch's DbContext configuration must match the database targeted by the process. The demo reuses ApplicationDbContext.Configure(builder, Configuration, ApplicationInformation.IsDevelopment).

Enabling commands

A class decorated with [Command] is not enough to make the command available. It must be declared as a subcommand, for example with [Subcommand(typeof(BatchCommand))] on Main.