xform-netapps is a C# library providing reusable building blocks and helpers for creating .NET applications of various types (Console, WinForms, Web API). It offers common services (configuration, certificate handling, GUID generation, logging, json serialization and deserialization) and app builders to streamline application startup and hosting. It's a library to accelerate development and standardize application architecture across multiple .NET app types.
- Unified configuration support via
IConfiguration(JSON, environment variables,.exe.config). - Default certificate chain validation with customizable behavior.
- Reusable sequential GUID generator for database-friendly IDs.
- Ready-to-use builders for Console, WinForms, and Web API applications.
- Unit-tested components for certificates, configuration, and GUID generation.
| Component / Class | Purpose / Responsibility |
|---|---|
| CertificateProvider | Load and manage X.509 certificates from stores or memory. Validate certificates, check expiration, and validate chains. |
| ConfigProxyProvider | Wrapper for reading configuration settings from .exe.config, JSON, and environment variables, with support for sensitive keys. |
| SequentialGuidProvider | Generates sequential GUIDs optimized for database insertion and indexing. |
| ConsoleAppBuilder | Helps build and configure console applications with pre-injected services like certificates and configuration. |
| WinFormsAppBuilder | Similar to ConsoleAppBuilder, but for WinForms applications, providing a ready-to-use host and services. |
| WebApiBuilder | Bootstraps Web API applications with default configuration, DI, and common services. |
| CommonAppBuilder / Shared Logic | Underlying shared logic used by the builders for configuring logging, DI, configuration, and certificates. |
Namespace:
XForm.NetApps.Providers
Implements:ICertificateProvider
Purpose: Provides functionality to retrieve, manage, and validate X.509 certificates from certificate stores or configuration settings.
CertificateProvider is a configurable utility that allows applications to load and validate X.509 certificates from certificate stores (LocalMachine or CurrentUser) or from in-memory lists.
It supports:
- Retrieving certificates by thumbprint
- Validating certificate chains
- Validating expiration dates
- Validating Subject Key Identifiers (SKI)
- Managing multiple certificate stores and configurations
Initializes a new instance using configuration from an appsettings file or any IConfiguration source.
var configuration = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.Build();
var provider = new CertificateProvider(configuration);appsettings.json Example:
{
"CertificateSettings": {
"IsEnabled": true,
"CertStoreLocation": "LocalMachine",
"CertStoreName": "My",
"Thumbprints": [
"A1B2C3D4E5F6A7B8C9D0E1F2A3B4C5D6E7F8A9B0"
],
"CaAuthorityKeyIdentifier": "123456ABCDEF"
}
}If the section is missing or invalid, a ConfigurationErrorsException will be thrown.
Creates the provider from a CertificateSettings object.
var settings = new CertificateSettings
{
IsEnabled = true,
CertStoreLocation = "LocalMachine",
CertStoreName = "My",
Thumbprints = new[] { "A1B2C3..." }
};
var provider = new CertificateProvider(settings);CertificateProvider(string[]? thumbprints, string? storeLocation = null, string? storeName = null, string? parentAki = null, bool isEnabled = true)
Manually specifies certificate store parameters.
var provider = new CertificateProvider(
thumbprints: new[] { "A1B2C3..." },
storeLocation: "CurrentUser",
storeName: "My"
);Initialize directly with a list of certificates (for in-memory scenarios).
var certs = new List<X509Certificate2> { rootCert, clientCert };
var provider = new CertificateProvider(certs);The configured store location (LocalMachine or CurrentUser).
The configured store name (e.g., My, Root, CertificateAuthority).
Default chain policy used for certificate validation:
RevocationMode = NoCheckVerificationFlags = NoFlagVerificationTimeIgnored = false
Retrieves a certificate from the provider’s in-memory collection by its thumbprint.
var cert = provider.GetCertificate("A1B2C3D4...");
if (cert != null)
{
Console.WriteLine($"Found certificate: {cert.Subject}");
}Returns null if not found.
Fetches a certificate directly from a specified store.
var cert = provider.GetCertificate(
"A1B2C3D4...",
StoreLocation.LocalMachine,
StoreName.My
);Adds certificates by thumbprints from the configured store and appends them to the internal list.
Returns thumbprints that were not found.
var thumbprints = new List<string> { "A1B2C3...", "XYZ123..." };
provider.AddCertificates(thumbprints, out var notFound);
if (notFound.Any())
{
Console.WriteLine($"Missing certs: {string.Join(", ", notFound)}");
}Adds a list of certificate objects to the existing collection.
var extraCerts = new List<X509Certificate2> { newCert1, newCert2 };
provider.AddCertificates(extraCerts);ValidateCertificateChain(X509Certificate2 certificate, out X509ChainStatus[] chainStatus, X509ChainPolicy? chainPolicy = null)
Validates a certificate chain using the configured certificates as potential issuers.
bool isValid = provider.ValidateCertificateChain(clientCert, out var chainStatus);
Console.WriteLine($"Valid chain: {isValid}");
foreach (var status in chainStatus)
{
Console.WriteLine($"Status: {status.StatusInformation}");
}Example with a custom chain policy:
var policy = new X509ChainPolicy
{
RevocationMode = X509RevocationMode.NoCheck,
VerificationFlags = X509VerificationFlags.AllowUnknownCertificateAuthority
};
bool isValid = provider.ValidateCertificateChain(clientCert, out var status, policy);If the provider is disabled, it throws InvalidOperationException.
Checks if a certificate is currently valid (not expired or not yet valid).
bool isValid = provider.ValidateCertificate(cert);
Console.WriteLine(isValid ? "Certificate is valid." : "Certificate is invalid or expired.");If the provider is disabled, throws InvalidOperationException.
ValidateSubjectKeyIdentifier(X509Certificate2 certificate, string? expectedSki = null, X509Certificate2? issuerCertificate = null)
Validates a certificate’s Subject Key Identifier (SKI) against an expected SKI, the issuer’s Authority Key Identifier (AKI), or the configured parent AKI.
bool skiValid = provider.ValidateSubjectKeyIdentifier(clientCert, expectedSki: "ABCD1234EF...");
Console.WriteLine($"SKI valid: {skiValid}");Or using issuer certificate:
bool skiMatchesIssuer = provider.ValidateSubjectKeyIdentifier(clientCert, issuerCertificate: caCert);If no SKI/AKI reference is provided (and none exists in config), an ArgumentNullException will be thrown.
Parses a string into a StoreLocation enum.
if (provider.TryParseStoreLocation("CurrentUser", out var loc))
{
Console.WriteLine($"Parsed store location: {loc}");
}Supported values and aliases:
CurrentUser— aliases:"user","current","currentuser"LocalMachine— aliases:"machine","localmachine"
Returns true when parsing succeeds.
Parses a string into a StoreName enum.
if (provider.TryParseStoreName("Root", out var store))
{
Console.WriteLine($"Parsed store name: {store}");
}Supported values and aliases:
My— aliases:"personal","my"Root— aliases:"root","trustedroot","trusted"CertificateAuthority— aliases:"ca","certificateauthority"AuthRoot— aliases:"authroot","thirdpartyroot"TrustedPeople— aliases:"trustedpeople","people"TrustedPublisher— aliases:"trustedpublisher","publisher"Disallowed— aliases:"disallowed","revoked"
Returns true when parsing succeeds.
| Exception Type | Scenario |
|---|---|
ConfigurationErrorsException |
Missing or invalid configuration section or thumbprint |
ArgumentNullException |
Null argument to validation method |
InvalidOperationException |
Provider is disabled when a validation or retrieval method is called |
var configuration = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.Build();
var provider = new CertificateProvider(configuration);
// Get a certificate
var cert = provider.GetCertificate("A1B2C3D4...");
// Validate it
if (provider.ValidateCertificate(cert))
{
Console.WriteLine("Certificate is within its validity period.");
}
// Validate chain
bool validChain = provider.ValidateCertificateChain(cert, out var chainStatus);
Console.WriteLine($"Chain valid: {validChain}");- The provider does not automatically trust self-signed certificates unless present in the configured store or passed into the provider's certificate list.
- The
DefaultChainPolicyavoids revocation checks by default to simplify usage in test and development environments. - Thumbprints are case-insensitive and can include or omit spaces.
- Use
AddCertificateswithnotFoundThumbprintsto detect missing certificates at runtime.
ConfigProxyProvider allows reading application settings and connection strings from the application's .exe.config file and system environment variables. Settings from the application configuration file take precedence over environment variables.
public NameValueCollection AppSettings { get; }Returns the application settings read from the .exe.config file.
public ConnectionStringSettingsCollection ConnectionStrings { get; }Returns the collection of connection strings used to configure database connections.
var provider = new ConfigProxyProvider();Initializes the provider using the default application configuration file and system environment variables.
var provider = new ConfigProxyProvider("C:\\MyApp\\MyApp.exe.config", "ENV_");pathToApplicationConfigFile– Path to the application's.exe.configfile.environmentSettingNamePrefix– Optional prefix for environment variables to filter only application-specific keys.
Throws ArgumentException if the file does not exist.
Note: If you use the default configuration, system-level connection strings (like
SQLEXPRESS) may also be loaded.
public T? GetAppSetting<T>(string key)Gets the value of the app setting with the specified key. Throws KeyNotFoundException if the key is not found. Throws InvalidCastException if conversion fails.
Example:
string appName = provider.GetAppSetting<string>("AppName");
int retryCount = provider.GetAppSetting<int>("RetryCount");public T? GetAppSetting<T>(string key, T? defaultValue)Gets the value of the app setting with the specified key. Returns defaultValue if the key is not found.
Example:
int retryCount = provider.GetAppSetting<int>("RetryCount", 3); // returns 3 if key not found
string logPath = provider.GetAppSetting<string>("LogPath", "C:\\Logs");public Dictionary<string, IDictionary<string, string?>> GetAllSettings()Returns all settings from both environment variables and application settings. The returned dictionary contains two entries:
"Environment"– filtered environment variables with prefix (if provided)"AppSettings"– application settings
Sensitive keys containing "pass", "secret", or "key" are masked.
Example:
var allSettings = provider.GetAllSettings();
foreach (var envSetting in allSettings["Environment"])
{
Console.WriteLine($"{envSetting.Key} = {envSetting.Value}");
}
foreach (var appSetting in allSettings["AppSettings"])
{
Console.WriteLine($"{appSetting.Key} = {appSetting.Value}");
}var provider = new ConfigProxyProvider();
// Read an application setting
string appName = provider.GetAppSetting<string>("AppName");
// Read a setting with default value
int maxRetries = provider.GetAppSetting<int>("MaxRetries", 5);
// Read all settings
var settings = provider.GetAllSettings();var provider = new ConfigProxyProvider(@"C:\\MyApp\\MyApp.exe.config", "ENV_");
// Read app setting
string connectionString = provider.GetAppSetting<string>("DefaultConnection");
// Get all environment-specific and app settings
var allSettings = provider.GetAllSettings();try
{
string missingSetting = provider.GetAppSetting<string>("MissingKey");
}
catch (KeyNotFoundException ex)
{
Console.WriteLine("Setting not found: " + ex.Message);
}
// Using default value instead
string value = provider.GetAppSetting<string>("MissingKey", "default-value");Note:
- Application settings take precedence over environment variables.
- Sensitive keys are masked automatically in
GetAllSettings(). - The class implements
IConfigProxyProviderand can be used wherever dependency injection is supported.
Namespace: XForm.NetApps.Providers
Implements: ISequentialGuidProvider
SequentialGuidProvider generates sequential GUIDs optimized for databases and indexing. Using sequential GUIDs instead of purely random GUIDs can reduce fragmentation in indexes and improve insert performance in database systems like SQL Server.
Generates a new sequential GUID.
Parameters:
guidType(optional): Specifies the type of sequential GUID to generate. Default isSequentialAtEndFromGuid.
Returns:
Guid – A newly generated sequential GUID.
Example:
var provider = new SequentialGuidProvider();
// Default sequential GUID (SQL Server optimized)
Guid defaultGuid = provider.NewGuid();
Console.WriteLine(defaultGuid);
// Sequential GUID as string
Guid stringGuid = provider.NewGuid(SequentialGuidType.SequentialAsString);
Console.WriteLine(stringGuid);
// Sequential GUID as binary
Guid binaryGuid = provider.NewGuid(SequentialGuidType.SequentialAsBinary);
Console.WriteLine(binaryGuid);Namespace: XForm.NetApps.Builders.Console
ConsoleAppBuilder provides helper methods to build and configure a console application host with commonly injected services. It simplifies creating IHostBuilder and HostApplicationBuilder instances for console applications. The common services that are automatically injected are ISequentialGuidProvider, IJsonUtilities, IConfigProxyProvider, and ICertificateProvider.
Builds and returns an IHostBuilder for a console application with injected common services.
Parameters:
appOptions– AConsoleAppOptionsobject containing:AppName(string): Name of the console application. Required.Args(string[]): Command-line arguments.
Returns:
IHostBuilder – Configured host builder.
appsettings.json Example:
{
"ApplicationName": "Sample Console Application",
"Description": "Description of the app",
"DOTNET_ENVIRONMENT": "development",
// Path of the app.exe.config or app.dll.config to load the legacy configuration from. This path must be either absolute or relative to the exe/dll to which it belongs.
"AppConfigPath": "MySampleConsoleApp.dll.config", // Path to app.config of the worker, either relative to dll containing CommonServicesInjector, or the absolute path. The folder structure is created during the packaging of windows service on build server.
// AssemblyProvider configuration is used to load any dependencies (assemblies) at the startup of the host application.
"AssemblyProvider": {
"FileProviders": [
{
"Key": "PhysicalAssemblies",
"IsWritable": false,
// File provider factory that will load the assemblies from a physical folder.
// This type must implement the interface XForm.Core.Interfaces.IFileProviderFactory.
"Factory": "XForm.NetApps.Providers.File.PhysicalFileProviderFactory",
// The default root folder for all assemblies to be loaded from.
// IUse value "BASE_DIRECTORY" to indicate the base directory of the host application.
"Root": "BASE_DIRECTORY"
}
]
},
// ServiceInjector - Injects the common services, needed by the application, at the host level. The specified type must implement the interface XForm.Core.Interfaces.IServicesInjector.
"ServiceInjector": {
"IsEnabled": true,
"AssemblyPath": "MySampleConsoleApp.dll", // Path of assembly containing the service injector for the email worker. The folder structure is created during the packaging of windows service on build server.
"TypeName": "MySampleConsoleApp.SampleExternalServiceInjector"
},
// Logger
"SeriLog": {
"Using": [ "Serilog.Sinks.File", "Serilog.Sinks.Console" ],
"MinimumLevel": "Information",
"WriteTo": [
{
"Name": "File",
"Args": {
"path": "..\\Logs\\SampleApplicationLog..log", // Two '.' have been intentionally added before extension. This helps Serilog to put date in the middle.
"rollingInterval": "Day",
"outputTemplate": "{Timestamp:o} | {Level:u1} | {ThreadId} | {ThreadName} | {Message:l} | {Properties:jl} | {Exception} | ***** End-of-Log-Entry *****{NewLine}",
"retainedFileCountLimit": 10
}
}
]
},
// Any additional config files to be loaded. The path is relative to the base directory of the host application.
// This is commented out to demonstrate loading config through command-line args instead of static config file.
//"AdditionalJsonConfigs": [
// "additional-command-args-settings.json"
//],
"CertificateSettings": {
"IsEnabled": false,
"CertStoreLocation": "LocalMachine",
"CertStoreName": "My",
"Thumbprints": [
// Add thumbrpints of all CA and Root certs to validate the cert chain of incoming clinet certificates
]
},
"MySampleSetting": "This is a sample setting",
// ConnectionStrings
"ConnectionStrings": {
"DbConnectionString": "<%DB_CONNECTION_STRING%>"
}
}Example:
using XForm.NetApps.Builders.Console;
using Microsoft.Extensions.Hosting;
var appOptions = new ConsoleAppOptions
{
AppName = "MyConsoleApp",
Args = args
};
IHostBuilder hostBuilder = ConsoleAppBuilder.CreateHostBuilder(appOptions);
hostBuilder.Build().Run();Namespace: XForm.NetApps.Builders.WinForms
WinFormsAppBuilder provides helper methods to create and configure a host for a WinForms application with common services already injected. It simplifies creating IHostBuilder and HostApplicationBuilder instances for WinForms applications. The common services that are automatically injected are ISequentialGuidProvider, IJsonUtilities, IConfigProxyProvider, and ICertificateProvider.
appsettings.json Example:
{
"ApplicationName": "Sample WinForms Application",
"Description": "Description of the app",
"DOTNET_ENVIRONMENT": "development",
// Path of the app.exe.config or app.dll.config to load the legacy configuration from. This path must be either absolute or relative to the exe/dll to which it belongs.
"AppConfigPath": "MySampleWinFormsApp.dll.config", // Path to app.config of the worker, either relative to dll containing CommonServicesInjector, or the absolute path. The folder structure is created during the packaging of windows service on build server.
// AssemblyProvider configuration is used to load any dependencies (assemblies) at the startup of the host application.
"AssemblyProvider": {
"FileProviders": [
{
"Key": "PhysicalAssemblies",
"IsWritable": false,
// File provider factory that will load the assemblies from a physical folder.
// This type must implement the interface XForm.Core.Interfaces.IFileProviderFactory.
"Factory": "XForm.NetApps.Providers.File.PhysicalFileProviderFactory",
// The default root folder for all assemblies to be loaded from.
// IUse value "BASE_DIRECTORY" to indicate the base directory of the host application.
"Root": "BASE_DIRECTORY"
}
]
},
// ServiceInjector - Injects the common services, needed by the application, at the host level. The specified type must implement the interface XForm.Core.Interfaces.IServicesInjector.
"ServiceInjector": {
"IsEnabled": true,
"AssemblyPath": "MySampleWinFormsApp.dll", // Path of assembly containing the service injector for the email worker, relative to service host. The folder structure is created during the packaging of windows service on build server.
"TypeName": "MySampleWinFormsApp.SampleExternalServiceInjector"
},
// Logger
"SeriLog": {
"Using": [ "Serilog.Sinks.File", "Serilog.Sinks.Console" ],
"MinimumLevel": "Information",
"WriteTo": [
{
"Name": "File",
"Args": {
"path": "..\\Logs\\SampleApplicationLog..log", // Two '.' have been intentionally added before extension. This helps Serilog to put date in the middle.
"rollingInterval": "Day",
"outputTemplate": "{Timestamp:o} | {Level:u1} | {ThreadId} | {ThreadName} | {Message:l} | {Properties:jl} | {Exception} | ***** End-of-Log-Entry *****{NewLine}",
"retainedFileCountLimit": 10
}
}
]
},
// Any additional config files to be loaded. The path is relative to the base directory of the host application.
"AdditionalJsonConfigs": [
"additional-config-settings.json"
],
"CertificateSettings": {
"IsEnabled": true,
"CertStoreLocation": "LocalMachine",
"CertStoreName": "My",
"Thumbprints": [
// Add thumbrpints of all CA and Root certs to validate the cert chain of incoming clinet certificates
]
},
"MySampleSetting": "This is a sample setting",
// ConnectionStrings
"ConnectionStrings": {
"DbConnectionString": "<%DB_CONNECTION_STRING%>"
}
}
Builds and returns an IHostBuilder for a WinForms application with injected common services.
Parameters:
-
appOptions– AWinFormsAppOptionsobject containing:AppName(string): Name of the WinForms application. Required.Args(string[]): Command-line arguments.
Returns:
IHostBuilder – Configured host builder.
Example:
using XForm.NetApps.Builders.WinForms;
using Microsoft.Extensions.Hosting;
var appOptions = new WinFormsAppOptions
{
AppName = "MyWinFormsApp",
Args = args
};
IHostBuilder hostBuilder = WinFormsAppBuilder.CreateHostBuilder(appOptions);
hostBuilder.Build().Run();Builds and returns a HostApplicationBuilder for a WinForms application with injected common services.
Parameters:
-
appOptions– AWinFormsAppOptionsobject containing:AppName(string): Name of the WinForms application. Required.Args(string[]): Command-line arguments.
Returns:
HostApplicationBuilder – Configured host application builder.
Example:
using XForm.NetApps.Builders.WinForms;
using Microsoft.Extensions.Hosting;
var appOptions = new WinFormsAppOptions
{
AppName = "MyWinFormsApp",
Args = args
};
HostApplicationBuilder builder = WinFormsAppBuilder.CreateAppHostBuilder(appOptions);
// Example: Register services for dependency injection
builder.Services.AddSingleton<MyService>();
var app = builder.Build();
app.Run();WinFormsAppBuilderrelies onCommonAppBuilderto configure shared services for the application.- The
AppNameproperty inWinFormsAppOptionsmust be provided; otherwise, an exception is thrown usingXssert. - The returned host builders can be further configured with additional services, logging, or hosted services as needed.
Namespace: XForm.NetApps.Builders.WebApi
Purpose: Creates and returns a HostApplicationBuilder or IHostBuilder for a WebApi application.
The WebApiBuilder class provides methods to create and configure a host builder for Web API applications. It allows you to initialize the application with common services and custom settings using WebApiOptions.
This class is static and contains only public methods.
appsettings.json Example:
{
"AllowedHosts": "*",
"ApplicationName": "Sample WebApi Application",
"Description": "Description of the app",
"DOTNET_ENVIRONMENT": "development",
// Path of the app.exe.config or app.dll.config to load the legacy configuration from. This path must be either absolute or relative to the exe/dll to which it belongs.
"AppConfigPath": "MySampleWebApi.dll.config", // Path to app.config of the worker, either relative to dll containing CommonServicesInjector, or the absolute path. The folder structure is created during the packaging of windows service on build server.
// AssemblyProvider configuration is used to load any dependencies (assemblies) at the startup of the host application.
"AssemblyProvider": {
"FileProviders": [
{
"Key": "PhysicalAssemblies",
"IsWritable": false,
// File provider factory that will load the assemblies from a physical folder.
// This type must implement the interface XForm.Core.Interfaces.IFileProviderFactory.
"Factory": "XForm.NetApps.Providers.File.PhysicalFileProviderFactory",
// The default root folder for all assemblies to be loaded from.
// IUse value "BASE_DIRECTORY" to indicate the base directory of the host application.
"Root": "BASE_DIRECTORY"
}
]
},
// ServiceInjector - Injects the common services, needed by the application, at the host level. The specified type must implement the interface XForm.Core.Interfaces.IServicesInjector.
"ServiceInjector": {
"IsEnabled": true,
"AssemblyPath": "MySampleWebApi.dll", // Path of assembly containing the service injector for the email worker, relative to service host. The folder structure is created during the packaging of windows service on build server.
"TypeName": "MySampleWebApi.SampleExternalServiceInjector"
},
// Logger
"SeriLog": {
"Using": [ "Serilog.Sinks.File", "Serilog.Sinks.Console" ],
"MinimumLevel": "Information",
"WriteTo": [
{
"Name": "File",
"Args": {
"path": "Logs\\SampleWebApiLog..log", // Two '.' have been intentionally added before extension. This helps Serilog to put date in the middle.
"rollingInterval": "Day",
"outputTemplate": "{Timestamp:o} | {Level:u1} | {ThreadId} | {ThreadName} | {Message:l} | {Properties:jl} | {Exception} | ***** End-of-Log-Entry *****{NewLine}",
"retainedFileCountLimit": 10
}
}
]
},
// Any additional config files to be loaded. The path is relative to the base directory of the host application.
// This is commented out to demonstrate loading config through command-line args instead of static config file.
"AdditionalJsonConfigs": [
"additional-web-api-settings.json"
],
"CertificateSettings": {
"IsEnabled": true,
"CertStoreLocation": "LocalMachine",
"CertStoreName": "My",
"Thumbprints": [
// Add thumbrpints of all CA and Root certs to validate the cert chain of incoming clinet certificates
]
},
"MySampleSetting": "This is a sample setting",
// ConnectionStrings
"ConnectionStrings": {
"DbConnectionString": "<%DB_CONNECTION_STRING%>"
}
}Description:
Builds and returns an IHostBuilder for a WebApi application with injected common services.
Parameters:
webApiOptions(WebApiOptions): Options including API name and arguments.
Returns:
IHostBuilder – Configured host builder for the WebApi application.
Exceptions:
- Throws
ArgumentNullExceptionifwebApiOptions.ApiNameis null.
Example:
using XForm.NetApps.Builders.WebApi;
using Microsoft.Extensions.Hosting;
var options = new WebApiOptions
{
ApiName = "MyWebApi",
Args = args
};
IHostBuilder hostBuilder = WebApiBuilder.CreateHostBuilder(options);
hostBuilder.Build().Run();Description:
Builds and returns a WebApplicationBuilder for a WebApi application. This method is suitable for minimal APIs or ASP.NET Core 6+ Web API projects.
Parameters:
webApiOptions(WebApiOptions): Options including API name and arguments.
Returns:
WebApplicationBuilder – Configured web application builder for WebApi.
Exceptions:
- Throws
ArgumentNullExceptionifwebApiOptions.ApiNameis null.
Example:
using XForm.NetApps.Builders.WebApi;
using Microsoft.AspNetCore.Builder;
var options = new WebApiOptions
{
ApiName = "MyWebApi",
Args = args
};
WebApplicationBuilder builder = WebApiBuilder.CreateWebApplicationBuilder(options);
var app = builder.Build();
app.MapGet("/", () => "Hello World!");
app.Run();- Always ensure
WebApiOptions.ApiNameis not null; otherwise, an exception will be thrown. - Use
CreateHostBuilderfor generic host scenarios. - Use
CreateWebApplicationBuilderwhen targetingWebApplicationand minimal APIs.
WebApiOptions: Holds configuration options for the WebApi builder including API name and command-line arguments.CommonAppBuilder: Provides shared logic for creating host builders across different app types.HostApplicationBuilderSettings: Settings used when configuring the application builder.
Namespace: XForm.NetApps.Providers
Implements: IDbContextProvider\
SqlDbContextProvider is a lightweight, disposable provider class for
managing SQL Server database connections and transactions.
It encapsulates a SqlConnection and exposes methods to open/close
connections, begin/commit/rollback transactions, and ensure proper
disposal.
This class is intended to be injected or used as a scoped database context within .NET applications.
public SqlDbContextProvider(string name, string connectionString)Parameters | Name | Type | Description |
|------|------|-------------| | name | string | A logical
name identifying this context instance. | | connectionString |
string | The connection string used to create the underlying
SqlConnection. |
Gets the context name assigned at initialization.
The underlying SQL connection.
Returns true if a transaction is active.
The active transaction object, if any.
Opens the underlying SQL connection if it is closed.
Closes the connection if it is open.
Begins a new SQL transaction. Throws if a transaction is already in progress or if the connection is uninitialized.
Commits the current transaction, if active.
Rolls back the current transaction, if active.
Releases all managed resources, rolls back any pending transactions, and disposes the connection.
Adding named context providers in .NET 8 using keyed services and then injecting them in the services/controllers.
builder.Services.AddKeyedSingleton<IDbContextProvider>("AppDb", (sp, key) =>
new SqlDbContextProvider("AppDb", builder.Configuration.GetConnectionString("AppDb"))
);
builder.Services.AddKeyedSingleton<IDbContextProvider>("LogsDb", (sp, key) =>
new SqlDbContextProvider("LogsDb", builder.Configuration.GetConnectionString("LogsDb"))
);
// Example usage in a controller
public class UserController
{
private readonly IDbContextProvider _db;
private readonly IDbContextProvider _logsDb;
public UserController([FromKeyedServices("AppDb")] IDbContextProvider db, [FromKeyedServices("LogsDb")] IDbContextProvider logsDb)
{
_db = db;
_logsDb = logsDb;
}
}Namespace: XForm.NetApps.Attibutes.Web\
The DbContextAttribute is an ASP.NET Core action filter designed to
manage database connection and transaction lifecycles for controller actions.
It automates opening, committing, rolling back, and closing database
connections and transactions based on the action’s execution outcome.
- Automatically opens a database connection before an action executes
- Optionally wraps actions inside a transaction
- Commits on HTTP 200 (success)
- Rolls back on exceptions or failed responses
- Closes the database connection after execution
- Provides structured logging for lifecycle events
- Supports multiple database connections using named connection strings
public DbContextAttribute(
bool executeInTransaction = true,
string dbConnectionStringName = "XformConnectionString"
)Determines if the action should be executed within a transaction.
Specifies the name of the connection string to use from configuration. Default is 'XformConnectionString'
Apply to a controller action:
[DbContext]
[HttpPost("create-order")]
public IActionResult CreateOrder([FromServices] IOrderService orderService)
{
orderService.CreateNewOrder();
return Ok("Order created successfully");
}Use without transactions:
[DbContext(executeInTransaction: false)]
public IActionResult GetStatus()
{
return Ok("Service running");
}Use a specific DB connection:
[DbContext(dbConnectionStringName: "ReadReplica")]
public IActionResult GetReadOnlyData()
{
return Ok("Read-only data");
}| Outcome | Action |
|---|---|
| No exception + HTTP 200 OK | ✅ Commit transaction |
| Exception thrown | 🔄 Rollback transaction |
| Non-200 response | 🔄 Rollback transaction |
| Transaction disabled | 🚫 No commit/rollback logic |
MIT License. See the LICENSE file in the project root for details.
- Added IDbContext (SqlDbContextProvider) to common services that are automatically injected in the host based on configuration setting 'ConnectionStrings'.
- Added ICertificateProvider implementation and added it into auto-injected core implementations in ConsoleAppBuilder.CreateAppHostBuilder, WinFormsAppBuilder.CreateAppHostBuilder, and WebApiBuilder.CreateWebApplicationBuilder implementations.
- Added unit tests around CertificateProvider, ConfigProxyProvider, and SequentialGuidProvider implementations.
- Added readme with sample usage.
- Removed unused code, reduced redundancy.
- Refactored code to follow the same IHostBuilder pattern for configuring the host for all kinds of applications except Windows Services.
- Initial commit for the desired functionality in library.