Jasper Command Line Support Edit on GitHub


Note! Jasper uses the related Oakton project for command line parsing and its command runner extensibility. "Oakton" is a small community just to the North of Jasper's namesake.

At this time, the Jasper team is focused on hosting applications either in IIS (or nginx) or as a console application that would be suitable for running in a Docker container. To that end, we've added the JasperHost static class as a helper for standing up Jasper in a console application. You obviously want to run the application from a command line, and Jasper certainly does that, but the real value is the additional diagnostic commands documented on this page that will help you diagnose problems or just generally understand your Jasper application better. The command line usage is also extensible.

If you're using IWebHostBuilder to bootstrap your application, you can opt into Jasper's expanded command line support with code similar to this hybrid MVC Core / Jasper application that utilizes an extension method called RunJasper(args) to execute a Jasper application at the command line:


public class Program
{
    // Return an int for a status code
    public static int Main(string[] args)
    {
        // Calling RunJasper() opts into Jasper's expansive
        // command line skeleton with diagnostics you probably
        // want
        return CreateWebHostBuilder(args).RunJasper(args);
    }

    public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .UseStartup<Startup>()

            // Add Jasper with all its defaults
            .UseJasper();
}

Likewise, this sample usage from the getting started topic for a headless Jasper application could look like this:



using Jasper;
using Jasper.CommandLine;

namespace MyApp
{
    internal class Program
    {
        private static int Main(string[] args)
        {
            // This bootstraps and runs the Jasper
            // application as defined by MyAppRegistry
            // until the executable is stopped
            return JasperHost.Run<MyAppRegistry>(args);
        }
    }
}

At runtime, JasperHost can use the JasperRegistry you hand it to bootstrap a IJasperHost and run the application until the console process is stopped.

Or again, if you'd prefer to bootstrap with IWebHostBuilder, you can still use JasperHost like this:


public static int Main(params string[] args)
{
    var builder = WebHost.CreateDefaultBuilder()
        .UseStartup<Startup>()
        .UseJasper();

    return JasperAgent.Run(builder, args);
}

You can also use the command line arguments to customize how the application runs like this:


static int Main(string[] args)
{
    return JasperAgent.Run<MyAppRegistry>(args, _ =>
    {
        if (args.Length == 1)
        {
            _.EnvironmentName = args[0];
        }
    });
}

Or like this:


static int Main(string[] args)
{
    // This gives you the ability to programmatically
    // construct the application based on the command line
    // arguments
    var registry = new JasperRegistry();


    return JasperAgent.Run(args, registry);
}

Let's say that your Jasper application compiles to MyApp.exe and uses the JasperHost class to run the commands. In that case you can run your application simply by typing MyApp at the command line with no arguments.

Overriding the Environment Name

For example, you can also use this syntax to run your application in "Development" mode:

MyApp run --environment Development

or

MyApp run -e Development

If you run this command, your application will start with JasperRegistry.EnvironmentName equal to Development. If you programmatically set the environment name in your JasperRegistry, that setting will win out over the command line flag.

Running with Verbose Console Tracing

Likewise, to see more verbose information on start up and runtime console tracing, use:

MyApp run --verbose

or

MyApp run -v

The -v / --verbose flags add console and debug logging to your system. It's the equivalent to calling:

Overriding the LogLevel

You can also override the log level of your application to any valid value of the LogLevel enumeration like this:

MyApp run --log-level Information

Validating the Configured Application

You may want to simply try to bootstrap the application and run all the environment tests and report out the results. That syntax is:

MyApp validate

which also respects the same --environment and --verbose flags as the run command. This command will bootstrap the application, run all the environment tests and start up validations, report on the success or failure, and shut down the application. Do note that if any environment tests fail, this command will return a non-zero return code that should be sufficient to let any build scripting tool you're using know that the validation failed.

The validate command will also validate the Lamar configuration and run any environment tests exposed through Lamar.

List Registered Services

Jasper only supports the Lamar container (the replacement for the venerable StructureMap container). To query the current state of service registrations, use this command:

MyApp services

And again, this command respects both the --environment and --verbose flags

Preview Generated Code

One of the easiest ways to debug message or HTTP handlers -- or just to understand their behavior -- is to read the generated code that Jasper is using to actually handle a specific message type or HTTP route. You can preview that code by using this command:

dotnet run -- code

Or to only see the code for message handlers:

dotnet run -- code messages

Or to only see the code for any HTTP handlers:

dotnet run -- code routes

Finally, to dump the results to a file, use the --file flag like this:

dotnet run -- code --file generated.cs

or

dotnet run -- code -f generated.cs

As usual, this command also respects both the --environment and --verbose flags

Describe Command

Just to preview information about your Jasper application, there's also the describe command that is used like this:

dotnet run -- describe

This will at least tell you what message types are handled and some basic information about any HTTP hosting.

Custom Commands

The Jasper.Console package uses the Oakton library for its command line support. You can add custom commands to your Jasper application by simply including OaktonCommand<T> classes in either the main application assembly or in any assembly that is decorated with the [JasperModule] attribute like so:


[assembly:JasperModule(typeof(DiagnosticsExtension))]

or without any kind of extension like so:


public class AppWithExtensions : JasperRegistry
{
    public AppWithExtensions()
    {
        // as is
        Include<CustomJasperExtension>();

        // or
        Include(new CustomJasperExtension());

        // or use the extension with customizations
        Include<CustomJasperExtension>(_ => { _.Threshold = 20; });
    }
}

If you want to write a command that uses the actual Jasper application, use the JasperInput class as either the input to your command or as the superclass to your input class:


public class JasperInput
{

    [Description("Use to override the ASP.Net Environment name")]
    public string EnvironmentFlag { get; set; }

    [Description("Write out much more information at startup and enables console logging")]
    public bool VerboseFlag { get; set; }

    [Description("Override the log level")]
    public LogLevel? LogLevelFlag { get; set; }

    [IgnoreOnCommandLine] public IWebHostBuilder WebHostBuilder { get; set; }

    [IgnoreOnCommandLine] public Assembly ApplicationAssembly { get; set; }

    public IJasperHost BuildHost(StartMode mode)
    {
        // SAMPLE: what-the-cli-is-doing

        // The --log-level flag value overrides your application's
        // LogLevel
        if (LogLevelFlag.HasValue) WebHostBuilder.ConfigureLogging(x => x.SetMinimumLevel(LogLevelFlag.Value));

        if (VerboseFlag)
        {
            Console.WriteLine("Verbose flag is on.");

            // The --verbose flag adds console and
            // debug logging, as well as setting
            // the minimum logging level down to debug
            WebHostBuilder.ConfigureLogging(x =>
            {
                x.SetMinimumLevel(LogLevel.Debug);

                x.AddConsole();
                x.AddDebug();
            });
        }

        // The --environment flag is used to set the environment
        // property on the IHostedEnvironment within your system
        if (EnvironmentFlag.IsNotEmpty()) WebHostBuilder.UseEnvironment(EnvironmentFlag);

To make that more concrete, here is how the built in services command uses JasperInput type to build out and use the running system:


[Description("Display the known Lamar service registrations")]
public class ServicesCommand : OaktonCommand<JasperInput>
{
    public override bool Execute(JasperInput input)
    {
        using (var runtime = input.BuildHost(StartMode.Lightweight))
        {
            Console.WriteLine(runtime.Container.WhatDoIHave());
        }

        return true;
    }
}

Do note that the command will be responsible for disposing and shutting down the running IJasperHost.

Message Storage

See Store and Forward Messaging for documentation on using the command line tooling to manage message storage.