Version

1.1.2

Next

Sample Applications

Previous

Logging Integration

Extensions


Jasper comes with its own extension system heavily influenced by its FubuMVC predecessor. The basic concept is just based on the IJasperExtension shown below:


public interface IJasperExtension
{
    void Configure(JasperOptions options);
}

So, what can you do in an extension? Basically anything you can configure in a Jasper application can be altered by an IJasperExtension. Here's a contrived example:


public class SampleExtension : IJasperExtension
{
    public void Configure(JasperOptions options)
    {
        // Add service registrations
        options.Services.AddTransient<IFoo, Foo>();



        // Alter settings within the application
        options.Advanced.JsonSerialization
            .TypeNameHandling = TypeNameHandling.All;
    }
}

Do note that in the case of service registrations and any kind of Settings.Apply() calls, the extension alterations are applied first before any registrations or declarations in the main JasperRegistry. What this means in effect is just that the application configuration takes precedence over extensions.

Now, on to how you would consume extensions in your projects:

Explicitly Loading Extensions

You can also explicitly create and consume IJasperExtension classes that are not automatically loaded through the [JasperModule] attribute that are be applied using the JasperRegistry.Include() method shown below:


var registry = new JasperOptions();
registry.Extensions.Include<OptionalExtension>();

Auto Discovery of Extensions

When you build an extension, you also have the option to make a single extension be auto-discoverable from an external assembly. To make that concrete, here's an auto-discovered extension in the Jasper.Marten library that wires up integration with a Marten database:


public class MartenExtension : IJasperExtension
{
    public void Configure(JasperOptions options)
    {
        options.Services.AddTransient<IEnvelopePersistence, PostgresqlEnvelopePersistence>();
        options.Services.AddSingleton(Options);

        options.Advanced.CodeGeneration.Sources.Add(new MartenBackedPersistenceMarker());

        var frameProvider = new MartenSagaPersistenceFrameProvider();
        options.Advanced.CodeGeneration.SetSagaPersistence(frameProvider);
        options.Advanced.CodeGeneration.SetTransactions(frameProvider);

        options.Services.AddSingleton<IDocumentStore>(x =>
        {
            var documentStore = new DocumentStore(Options);
            return documentStore;
        });

        options.Handlers.GlobalPolicy<FineGrainedSessionCreationPolicy>();


        options.Services.AddScoped(c => c.GetService<IDocumentStore>().OpenSession());
        options.Services.AddScoped(c => c.GetService<IDocumentStore>().QuerySession());

        options.Advanced.CodeGeneration.Sources.Add(new SessionVariableSource());

        options.Services.AddSingleton(s =>
        {
            return new PostgresqlSettings
            {
                // Super hacky, look away!!!
                ConnectionString = Options.Tenancy?.Default.CreateConnection().ConnectionString,
                SchemaName = Options.DatabaseSchemaName
            };
        });

    }

    public StoreOptions Options { get; } = new StoreOptions();
}

When a Jasper application is being bootstrapped, it looks for any assemblies in the application's bin directory that are marked with the [JasperModule] attribute to determine the extension types that should be automatically applied to the application. In the case above, the Marten extension would be discovered at bootstrapping time and the MartenExtension would be applied to the application.

Importing Http Endpoints or Message Handlers

It's perfectly possible to add additional HTTP routes or message handlers in extensions using the explicit JasperRegistry.Handlers.IncludeType() or JasperRegistry.Http.Actions.IncludeType() methods.