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.
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);
}
}
| Item | Role |
|---|---|
LagoonConsoleApplication.Run<Main>(args) | Initializes and runs the Lagoon console application. |
Main | Holds the application configuration and the list of subcommands. |
args | Contains the arguments passed from the command line. |
int | Represents 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.
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
| Responsibility | Method or attribute |
|---|---|
| Start the known commands | [Subcommand(typeof(...))] |
| Configure EF Core | OnConfigureDbContext(DbContextOptionsBuilder builder) |
| Register the business services | OnConfigureServices(IServiceCollection services) |
| Complete the status display | OnShowStatusAsync(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.
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.
| Parameter | Origin |
|---|---|
Main app | Instance of the Lagoon console application. |
MyFooService fooService | Service 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
The Batch's DbContext configuration must match the database targeted by the process. The demo reuses ApplicationDbContext.Configure(builder, Configuration, ApplicationInformation.IsDevelopment).
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.