Skip to content

Customization and Hosting

For direct construction without a host or DI container, see Without dependency injection.

Startup Hooks

StartupOptions lives in TcfOss.DatabaseManager.Core.Hosting, including when you use a provider wrapper. Hooks run after the library configures its services and before the host is built. ConfigureBuilder runs first, then ConfigureServices.

This complete Core wrapper example adds an application service without placeholder types:

using Microsoft.Extensions.DependencyInjection;
using TcfOss.DatabaseManager.Core.App;
using TcfOss.DatabaseManager.Core.Hosting;

var workingDirectory = Directory.GetCurrentDirectory();
var rawConfig = new GenericStartup().GetDefaultConfig(workingDirectory);
var result = new GenericStartApp().Start(
    rawConfig: rawConfig,
    workingDirectory: workingDirectory,
    options: new StartupOptions
    {
        ConfigureBuilder = builder => builder.Environment.ApplicationName = "MyApplication",
        ConfigureServices = services => services.AddSingleton(TimeProvider.System)
    });

var clock = result.Services.GetRequiredService<TimeProvider>();
Console.WriteLine(clock.GetUtcNow());

Use the same hooks with MySqlStartApp, MariaDbStartApp, or SqlServerStartApp. Provider startup still needs its own valid configuration.

Convenience Access

AppServiceProvider convenience accessors use thread-static state initialized by startup. They are not per-result state and should not be carried across async thread transitions. Prefer result.Services.CreateScope() and ordinary dependency injection, especially in asynchronous applications.

Wrapper startup builds a host but does not expose it through the returned result for explicit shutdown. Use the following approach when your application needs to own and dispose the host.

Manual Hosting

Install TcfOss.DatabaseManager.Core.Hosting for this standalone example. It registers generic services in a host owned by the caller.

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging.Abstractions;
using TcfOss.DatabaseManager.Core.App;
using TcfOss.DatabaseManager.Core.Hosting;
using TcfOss.DatabaseManager.Core.Parsing;

var workingDirectory = Directory.GetCurrentDirectory();
var startup = new GenericStartup();
var rawConfig = startup.GetDefaultConfig(workingDirectory);
var config = startup.BuildConfiguration(
    workingDirectory, rawConfig, new EnvironmentVariableReader(),
    relaxed: false, logger: NullLogger.Instance);

var builder = Host.CreateApplicationBuilder(new HostApplicationBuilderSettings
{
    ContentRootPath = workingDirectory,
    DisableDefaults = true
});
builder.Services.AddLogging();
builder.RegisterCommonServices(config);
builder.Services.RegisterGenericServices(config);

using var host = builder.Build();
var parser = host.Services.GetRequiredService<IParseText>();
var statements = parser.ParseText("CREATE TABLE widgets (id INT);");
Console.WriteLine($"Parsed {statements.Count} statement(s).");

RegisterCommonServices registers shared configuration and filesystem/parser dependencies. The dialect registration supplies its lexer, parser, formatting, and other supported services. Both registrations are required for this path.

For a caller-owned provider host, use its processed configuration and matching registration instead of RegisterGenericServices:

Package Startup/configuration builder Service registration Extension namespace
MySql.Hosting MyStartup / MyConfig RegisterMySqlServices TcfOss.DatabaseManager.MySql.Hosting
MariaDb.Hosting MaStartup / MyConfig RegisterMariaDbServices TcfOss.DatabaseManager.MariaDb.Hosting
MsSql.Hosting MsStartup / MsConfig RegisterMsSqlServices TcfOss.DatabaseManager.MsSql.Hosting

Build configuration using the selected startup's BuildConfiguration with a valid raw configuration, environment-variable reader, and logger, then call RegisterCommonServices and the corresponding dialect registration. Provider configuration may require connection information and contact the server; do not substitute a generic configuration object. See the provider prerequisites.

Choose one dialect registration per service container. Static shortcut access also requires separate initialization; the manual example intentionally uses DI instead.