Version

1.1.2

Next

Execution Pipeline

Previous

Getting Started

Bootstrapping & Configuration


As of the 1.0 release, Jasper plays entirely within the existing .Net Core ecosystem and depends on the generic hosting released as part of .Net Core 3.0 (IHostBuilder) for bootstrapping.

All Jasper configuration starts with the JasperOptions class and the UseJasper() extension method that hangs off of IHostBuilder.

Say that you are starting with the dotnet new worker template to build a headless Jasper application (i.e., no HTTP endpoints and no user interface of any kind). After adding a reference to the Jasper nuget, the Program class would look like this:


public class Program
{
    // The Jasper-ified version
    public static Task<int> Main(string[] args)
    {
        return CreateHostBuilder().RunJasper(args);
    }

    public static IHostBuilder CreateHostBuilder() =>
        Host.CreateDefaultBuilder()

            // This adds Jasper with a default JasperOptions
            .UseJasper()

            .ConfigureServices((hostContext, services) =>
            {
                // If you're not familiar with IHostedService,
                // it's a .Net Core mechanism to start and stop
                // long running routines within a .Net Core application
                services.AddHostedService<Worker>();
            });
}

Do be aware that Jasper can only function with Lamar as the underlying IoC container and the call to UseJasper() quietly replaces the built in ASP.Net Core DI container with Lamar.

See IoC Container Integration for more information.

Applying Jasper to a .Net Generic Host

We already saw above how to call UseJasper() with no arguments to add Jasper with all the defaults, but outside of using Jasper as just an in memory mediator, you'll need some further configuration.

If your Jasper configuration is relatively simple, you can modify the JasperOptions directly as shown in this overload of UseJasper(Action<JasperOptions>):


public static IHostBuilder CreateHostBuilder() =>
    Host.CreateDefaultBuilder()

        // This adds Jasper with inline configuration
        // of JasperOptions
        .UseJasper(opts =>
        {
            opts.Extensions.UseMessageTrackingTestingSupport();
        });

If you need to lookup configuration items like connection strings, ports, file paths, and other similar items from application configuration -- or need to vary the Jasper configuration by hosting environment -- you can use this overload:


public static IHostBuilder CreateHostBuilder() =>
    Host.CreateDefaultBuilder()

        // This adds Jasper with inline configuration
        // of JasperOptions
        .UseJasper((context, opts) =>
        {
            // This is an example usage of the application's
            // IConfiguration inside of Jasper bootstrapping
            var port = context.Configuration.GetValue<int>("ListenerPort");
            opts.Endpoints.ListenAtPort(port);

            // If we're running in development mode and you don't
            // want to worry about having all the external messaging
            // dependencies up and running, stub them out
            if (context.HostingEnvironment.IsDevelopment())
            {
                // This will "stub" out all configured external endpoints
                opts.Endpoints.StubAllExternallyOutgoingEndpoints();

                opts.Extensions.UseMessageTrackingTestingSupport();
            }
        });

Lastly, if you have more complex Jasper configuration, you may want to opt for a custom JasperOptions type. Let's say we have a class called CustomJasperOptions that inherits from JasperOptionslike this:


public class MyJasperApp : JasperOptions
{
    public MyJasperApp()
    {
        ServiceName = "My Jasper App";

        Endpoints.ListenAtPort(2111).Durable();
    }
}

That can be applied to a .Net Core application like this:


public static IHostBuilder CreateHostBuilder() =>
    Host.CreateDefaultBuilder()
        .UseJasper<CustomJasperOptions>();

Jasper with ASP.Net Core

Adding Jasper to an ASP.Net Core application -- with or without MVC -- isn't really any different. You still use the UseJasper() extension method like in this example:


public class Program
{
    // Change the return type to Task<int> to communicate
    // success/failure codes
    public static Task<int> Main(string[] args)
    {
        return CreateHostBuilder(args)

            // This replaces Build().Start() from the default
            // dotnet new templates
            .RunJasper(args);
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)

            // You can do the Jasper configuration inline with a 
            // Lambda, but here I've centralized the Jasper
            // configuration into a separate class
            .UseJasper<JasperConfig>()

            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            });
}

JasperOptions

The custom JasperOptions class shown below demonstrates the main features you can configure or extend for a Jasper application:


public class JasperOptionsWithEverything : JasperOptions
{
    public JasperOptionsWithEverything()
    {
        // This is strictly for logging and diagnostics identification
        // By default, this is just the name of the main application
        // assembly
        ServiceName = "MyService";

        // Extensions lets you apply or query Jasper extensions
        Extensions.UseMessageTrackingTestingSupport();

        // Idiomatic Lamar service registrations to be applied to the
        // application's underlying IoC container
        Services.For<IClock>().Use<Clock>();

        // Fine-tune how message handler types are discovered
        // and built. Also allows you to add middleware policies
        Handlers.DisableConventionalDiscovery();
    }

    // This method is an optional override for additional
    // Jasper configuration that is dependent upon either the
    // hosting environment name or the application configuration
    public override void Configure(IHostEnvironment hosting, IConfiguration config)
    {
        // Endpoints controls everything about where and how
        // Jasper receives incoming or sends outgoing messages
        // For the moment, this also gives you access to fine-tuning
        // the in-process worker queues for the local transport

        var incomingPort = config.GetValue<int>("incoming_port");
        Endpoints.ListenAtPort(incomingPort);

        var outgoingPort = config.GetValue<int>("outgoing_port");
        Endpoints.PublishAllMessages().ToPort(outgoingPort);
        Endpoints.LocalQueue("worker1").Sequential();
    }
}

The major areas are: