Skip to content

core bootstrap builder

Brian Greco edited this page Mar 25, 2023 · 2 revisions

IMAGE Bootstrap Builder

This topic discusses bootstrapping a microservice from a set of plugins. The example microservice built in the prior topic consisted on one Host plugin and 3 Application plugins. While not typically added to a specific microservice solution, a Core plugin was added for used in upcoming topics.

Under the hood, a CompositeContainer class is populated from a set of plugins from which the microservice will be bootstrapped. After the composite-container is composed, the end result is the creation of a CompositeApp instance that can be started by the host. This topic will discuss the code that is placed within the Program.cs to bootstrap the service.


IMAGE NetFusion is non-intrusive since it adds service-components to Microsoft's dependency-injection container. These registered components can then be injected into application-components at runtime. Plugin Modules, discussed in the next section, are responsible for initializing and configuring these service-components before they are added to the dependency-inject container.


ICompositeContainerBuilder

Plugins are added to the CompositeContainer by calling methods on the ICompositeContainerBuilder interface. An extension method named CompositeContainer declared on Microsoft's IServiceCollection interface is called to obtain a reference. The following shows the bootstrap code currently existing in the example microservice:

// Add Plugins to the Composite-Container:
builder.Services.CompositeContainer(builder.Configuration, new SerilogExtendedLogger())
    .AddSettings()

    .AddPlugin<CrossCutPlugin>()

    .AddPlugin<InfraPlugin>()
    .AddPlugin<AppPlugin>()
    .AddPlugin<DomainPlugin>()
    .AddPlugin<WebApiPlugin>()
    .Compose();

After all plugins are added, the Compose method is called after which no additional plugins can be added. When the compose method is called, the bootstrapping of each registered plugin begins. The bootstrap process will be discussed at length when discussing Plugin Modules since the modules added to a plugin contain the code that is invoked during bootstrapping.

Plugin Extension Method

To make adding a plugin to the composite-application even easier, many of the plugins provided by NetFusion define an extension method that can be called directly. Below is an example of an extension method provided by the RabbitMQ plugin:

public static class CompositeBuilderExtensions
{
    // Adds the RabbitMQ plugin to the composite application.
    public static ICompositeContainerBuilder AddRabbitMq(this ICompositeContainerBuilder composite)
    {
        return composite
            .AddSettings()
            .AddMessaging()
            .AddPlugin<RabbitMqPlugin>()
                
            // Extend the base messaging pipeline by adding the RabbitMqPublisher.
            .InitPluginConfig<MessageDispatchConfig>(config => 
                config.AddPublisher<RabbitMqPublisher>());
    }
}

The above extension method completes the following:

  • Adds the plugins on which the implementation is dependent: Settings and Messaging plugins.
  • Adds the plugin class implemented by the RabbitMQ plugin.
  • The RabbitMQ publishes command and domain-events by extending the messaging pipeline provided by the messaging plugin. This is why the messaging plugin is added as a dependency by calling the AddMessaging method.
  • Then the plugin extends the base messaging pipeline by obtaining the Message Plugin's MessageDispatchConfig configuration and adding a publisher that will direct published message to RabbitMQ.

The following shows how a microservice would be bootstrapped to used the RabbitMQ plugin:

// Add Plugins to the Composite-Container:
builder.Services.CompositeContainer(builder.Configuration, new SerilogExtendedLogger())
    .AddSettings()
  
  	.AddRabbitMq() // <-- Added this line

    .AddPlugin<CrossCutPlugin>()

    .AddPlugin<InfraPlugin>()
    .AddPlugin<AppPlugin>()
    .AddPlugin<DomainPlugin>()
    .AddPlugin<WebApiPlugin>()
    .Compose();

Starting Composite Application

Calling the compose executes methods on each plugin module in a well defined order. When the plugins are composed, they initialize all of state required so they can be started. For example, when the NetFusion.Integration.ServiceBus plugin is composed, it collects all of the meta-data required to determine which Queues, Topics, and Subscriptions should be created. However, a connection to ServiceBus is not established and the entities created until the CompositeApp is started.


IMAGE The ICompositeApp instance represents the built application composed from plug-ins.


Referencing and starting the CompositeApp is the last step of the bootstrap process until the host is stopped and the CompositeApp is instructed to stop. After the Compose method is called an instance of the created CompositeApp is registered within the dependency-injection container and can be referenced as ICompositeApp. The following code shows referencing IComposeApp and starting the Web Service and composite-application:

// ...

var app = builder.Build();

//...

// Reference the Composite-Application to start the plugins then
// start the web application.
var compositeApp = app.Services.GetRequiredService<ICompositeApp>();
var lifetime = app.Services.GetRequiredService<IHostApplicationLifetime>();

lifetime.ApplicationStopping.Register(() =>
{
    compositeApp.Stop();
    Log.CloseAndFlush();
});

var runTask = app.RunAsync();
await compositeApp.StartAsync();
await runTask;

Note that it is important call the RunAsync method on the WebApplication before starting the composite-application. This should be done so the Web Server can start accepting requests while the composite-application is bootstrapped. When running microservices within a container orchestrator such as Kubernetes, it will make web requests to determine when the microservice has been started so it can begin routing requests. The monitoring topic contains information about start, health, and readiness checks.

When the host is stopped, the Stop method is called on ICompositeApp. This call is made from a delegate invoked when the ApplicationStopping event is raised on the IHostApplicationLifetime service.

Summary

When reusing shared functionality among microservices, the Host application often has to understand the details required to register and configure reusable services. This becomes a maintenance issue when a reusable assembly is used among several Microservices.

NetFusion solves this issue by encapsulating the initialization and configuration of a reusable services behind a concept of a plug-n. Instead of having to configure and register services, all the Host application is responsible for is added plugins to the Composite Application. Plugins are added by referencing the ICompositeContainerBuilder returned from the IServiceCollection extension method.

After the plugins are added, and the Compose method is invoked on the ICompositeContainerBuilder interface, all plugins will have been called and their available services configured and added to the IServiceCollection DI Container. These services can then be injected as normal into application specific components.

Clone this wiki locally