SiLA2.AspNetCore 10.3.3

dotnet add package SiLA2.AspNetCore --version 10.3.3
                    
NuGet\Install-Package SiLA2.AspNetCore -Version 10.3.3
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="SiLA2.AspNetCore" Version="10.3.3" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="SiLA2.AspNetCore" Version="10.3.3" />
                    
Directory.Packages.props
<PackageReference Include="SiLA2.AspNetCore" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add SiLA2.AspNetCore --version 10.3.3
                    
#r "nuget: SiLA2.AspNetCore, 10.3.3"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package SiLA2.AspNetCore@10.3.3
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=SiLA2.AspNetCore&version=10.3.3
                    
Install as a Cake Addin
#tool nuget:?package=SiLA2.AspNetCore&version=10.3.3
                    
Install as a Cake Tool

SiLA2.AspNetCore

ASP.NET Core Integration Utilities for SiLA2 Servers

SiLA2.AspNetCore is the integration layer between ASP.NET Core and the SiLA2 C# implementation, providing essential extension methods, configuration utilities, and dependency injection patterns for building production-ready SiLA2 gRPC servers.

This module simplifies server setup by automating common tasks like:

  • Dependency injection configuration
  • Kestrel web server setup with automatic TLS/SSL certificate handling
  • SiLA2 feature initialization from .sila.xml files
  • Writable configuration pattern for runtime settings updates
  • Command-line argument parsing for server configuration
Package SiLA2.AspNetCore (NuGet)
Repository https://gitlab.com/SiLA2/sila_csharp
License MIT
Target .NET 10
Dependencies SiLA2.Core, Microsoft.Extensions.Hosting.Abstractions

Key Features

  • One-Line Server Setup - AddSiLA2Server() registers all essential services with a single call
  • Extension Methods for Dependency Injection - Streamlined service registration with AddSiLA2CoreServices(), AddSiLA2CertificateServices(), and more
  • Kestrel Server Configuration - Automatic TLS/SSL certificate handling with GetKestrelConfigData() and ListenSiLA2()
  • SILA_* Environment Variables - Container-friendly configuration compatible with the SiLA-Box
  • Persistent Container Identity - SILA_DATA_DIR keeps the server UUID and certificate across container recreation
  • Feature Auto-Discovery - Loads all .sila.xml feature definitions from the Features directory
  • Writable Options Pattern - Runtime configuration updates that persist to appsettings.json
  • Command-Line Argument Parsing - Override server IP, port, and certificate via CLI arguments
  • Integration with SiLA2.Utils - Seamless connection to networking, security, and configuration services

Installation

NuGet Package Manager

Install-Package SiLA2.AspNetCore

.NET CLI

dotnet add package SiLA2.AspNetCore

Project Reference (Development)

<ItemGroup>
  <ProjectReference Include="..\SiLA2.AspNetCore\SiLA2.AspNetCore.csproj" />
</ItemGroup>

Note: This package is required for all ASP.NET Core-based SiLA2 servers. It depends on SiLA2.Core which will be installed automatically.


Quick Start

Here's a minimal SiLA2 server using ASP.NET Core with the AddSiLA2Server() extension method:

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Server.Kestrel.Core;
using Microsoft.Extensions.DependencyInjection;
using SiLA2.AspNetCore;
using SiLA2.Server;
using YourFeature.Services;

var builder = WebApplication.CreateBuilder(args);

// Register all SiLA2 services with one call
builder.Services.AddSiLA2Server(builder.Configuration, options =>
{
    options.EnableGrpcReflection = true;  // Optional: enable for debugging
});

// Register feature services
builder.Services.AddSingleton<MyFeatureService>();

// Configure Kestrel with automatic certificate handling
builder.WebHost.ConfigureKestrel(options =>
{
    options.ListenSiLA2(args.GetKestrelConfigData(options.ApplicationServices));
});

var app = builder.Build();

// Initialize SiLA2 features from Features/*.sila.xml files
var siLA2Server = app.Services.GetRequiredService<ISiLA2Server>();
app.InitializeSiLA2Features(siLA2Server);

// Map gRPC services
app.MapGrpcService<MyFeatureService>();

// Start mDNS announcement
siLA2Server.Start();

app.Run();

Configuration (appsettings.json):

{
  "ServerConfig": {
    "Name": "MyDevice",
    "UUID": "12345678-1234-1234-1234-123456789012",
    "FQHN": "localhost",
    "Port": 50051
  }
}

Run the server:

dotnet run
# Or with custom IP/port:
dotnet run -- 192.168.1.100 50052

Extension Methods

AddSiLA2Server()

Registers all essential SiLA2 server services with a single call. This is the recommended way to configure a SiLA2 server.

Signature:

public static IServiceCollection AddSiLA2Server(
    this IServiceCollection services,
    IConfiguration configuration,
    Action<SiLA2ServerOptions> configureOptions = null)

Options:

  • EnableBinaryTransfer - Enable upload/download repositories (default: false)
  • EnableGrpcReflection - Enable gRPC reflection service (default: false)
  • EnableDetailedErrors - Enable detailed gRPC errors (default: true)
  • ServerConfigSectionName - Configuration section name (default: "ServerConfig")

Example:

var builder = WebApplication.CreateBuilder(args);

// Register all SiLA2 services with one call
builder.Services.AddSiLA2Server(builder.Configuration, options =>
{
    options.EnableBinaryTransfer = true;
    options.EnableGrpcReflection = true;
});

// Register feature-specific services
builder.Services.AddSingleton<MyFeatureService>();

Services Registered:

  • gRPC with standard SiLA2 interceptors (Logging, MetadataValidation, ParameterValidation)
  • MetadataManager for handling request/response metadata
  • Network discovery services (ServiceDiscoveryInfo, ServerInformation, IServiceAnnouncer)
  • Core server services (ISiLA2Server, IServerDataProvider, IGrpcChannelProvider)
  • Certificate services (ICertificateProvider, ICertificateContext, ICertificateRepository)
  • Observable command support (IObservableCommandManager<,>)
  • IServerConfig from configuration

AddSiLA2Grpc()

Adds gRPC services with standard SiLA2 interceptors for logging, metadata validation, and parameter validation.

Signature:

public static IServiceCollection AddSiLA2Grpc(
    this IServiceCollection services,
    bool enableDetailedErrors = true)

Example:

// Use this if you need more control than AddSiLA2Server provides
services.AddSiLA2Grpc(enableDetailedErrors: true);

Interceptors Added:

  • LoggingInterceptor - Logs all incoming requests and errors
  • MetadataValidationInterceptor - Validates request metadata
  • ParameterValidationInterceptor - Validates request parameters

AddSiLA2CoreServices()

Adds core SiLA2 server services. Use this if you need granular control over service registration.

Signature:

public static IServiceCollection AddSiLA2CoreServices(this IServiceCollection services)

Services Registered: | Service | Lifetime | |---------|----------| | MetadataManager | Singleton | | IObservableCommandManager<,> | Singleton (open generic) | | INetworkService | Transient | | ServiceDiscoveryInfo | Singleton | | ServerInformation | Singleton | | IServiceAnnouncer | Transient | | ISiLA2Server | Singleton | | IGrpcChannelProvider | Singleton | | IServerDataProvider | Scoped |


AddSiLA2CertificateServices()

Adds TLS/SSL certificate services for secure gRPC communication.

Signature:

public static IServiceCollection AddSiLA2CertificateServices(
    this IServiceCollection services,
    IConfiguration configuration = null)

Services Registered: | Service | Lifetime | |---------|----------| | ICertificateProvider | Singleton | | ICertificateContext | Singleton | | ICertificateRepository | Singleton |

When configuration is supplied and SILA_DATA_DIR is set, the certificate store is pointed at that directory instead of the assembly directory. AddSiLA2Server() passes the configuration automatically; the parameter is optional so existing call sites keep working unchanged.


AddSiLA2BinaryTransfer()

Adds binary transfer services for file upload and download functionality.

Signature:

public static IServiceCollection AddSiLA2BinaryTransfer(this IServiceCollection services)

Services Registered: | Service | Lifetime | |---------|----------| | IBinaryUploadRepository | Singleton | | IBinaryDownloadRepository | Singleton |


AddSiLA2ServerConfig()

Adds IServerConfig from the application configuration with writable options support.

Signature:

public static IServiceCollection AddSiLA2ServerConfig(
    this IServiceCollection services,
    IConfiguration configuration,
    string sectionName = "ServerConfig")

Required Configuration Values:

  • Name - The server display name
  • UUID - The server unique identifier (GUID)
  • FQHN - The fully qualified host name or IP address
  • Port - The server port number

Optional Configuration Values:

  • NetworkInterface - The network interface to bind to
  • DiscoveryServiceName - The mDNS service name

Example (appsettings.json):

{
  "ServerConfig": {
    "Name": "MyDevice",
    "UUID": "12345678-1234-1234-1234-123456789012",
    "FQHN": "localhost",
    "Port": 50051,
    "NetworkInterface": "0.0.0.0",
    "DiscoveryServiceName": "_sila2._tcp.local."
  }
}

GetKestrelConfigData()

Parses command-line arguments and retrieves Kestrel server configuration (IP address, port, TLS certificate).

Signature:

public static Tuple<IPAddress, int, X509Certificate2> GetKestrelConfigData(
    this string[] args,
    IServiceProvider serviceProvider)

Returns:

  • Item1 - IPAddress to bind to (defaults to IPAddress.Any)
  • Item2 - Port number
  • Item3 - X509Certificate2 for TLS/SSL, or null when SILA_TLS=false

Example:

builder.WebHost.ConfigureKestrel(options =>
{
    options.ListenSiLA2(args.GetKestrelConfigData(options.ApplicationServices));
});

Command-Line Arguments:

# Override IP and port
dotnet run -- 127.0.0.1 50051

# Use default configuration
dotnet run

Requirements:

  • ICertificateProvider must be registered in DI container
  • IServerConfig must be registered in DI container

ListenSiLA2()

Binds Kestrel to the address, port and certificate returned by GetKestrelConfigData().

Signature:

public static void ListenSiLA2(
    this KestrelServerOptions serverOptions,
    Tuple<IPAddress, int, X509Certificate2> configData)

Example:

builder.WebHost.ConfigureKestrel(options =>
{
    options.ListenSiLA2(args.GetKestrelConfigData(options.ApplicationServices));
});

Prefer this over calling Listen(...) and UseHttps(...) yourself. It handles two failure modes that are silent otherwise:

  • UseHttps(null) does not disable TLS. Kestrel falls back to the ASP.NET Core development certificate, so a server started with SILA_TLS=false still serves HTTPS — with a certificate no SiLA client trusts.
  • A plaintext Http1AndHttp2 endpoint is not a gRPC endpoint. HTTP/2 is normally negotiated through TLS ALPN, so without TLS Kestrel resolves the endpoint down to HTTP/1.1 (logging "HTTP/2 is not enabled … Connections to this endpoint will use HTTP/1.1") and gRPC stops working entirely. ListenSiLA2() sets HttpProtocols.Http2 explicitly on the plaintext path, so cleartext gRPC is served as h2c.

InitializeSiLA2Features()

Discovers and loads all .sila.xml feature definition files from the Features/ directory into the SiLA2 server.

Signature:

public static void InitializeSiLA2Features(
    this IHost host,
    ISiLA2Server siLA2Server)

Example:

var app = builder.Build();
var siLA2Server = app.Services.GetRequiredService<ISiLA2Server>();

// Load all Features/*.sila.xml files
app.InitializeSiLA2Features(siLA2Server);

// Now map gRPC services
app.MapGrpcService<TemperatureControllerService>();

Initialization Order (Critical):

1. builder.Build() → creates IHost
2. app.InitializeSiLA2Features(siLA2Server) → loads .sila.xml files
3. app.MapGrpcService<T>() → registers gRPC endpoints
4. siLA2Server.Start() → announces services via mDNS
5. app.Run() → starts server

What It Does:

  1. Finds the assembly's Features/ subdirectory
  2. Discovers all .sila.xml files
  3. Loads feature definitions into the server for:
    • Parameter validation
    • Error handling
    • Metadata access
    • Server introspection

Feature Directory Structure:

MyServer.App/
├── Features/
│   ├── TemperatureController-v1_0.sila.xml
│   ├── DataTypeProvider-v1_0.sila.xml
│   └── SiLAService-v1_0.sila.xml
└── Program.cs

ConfigureWritable<T>()

Registers the writable options pattern, enabling runtime configuration updates that persist to appsettings.json.

Signature:

public static void ConfigureWritable<T>(
    this IServiceCollection services,
    IConfigurationSection section,
    string file = "appsettings.json") where T : class, new()

Example:

// In Program.cs
services.ConfigureWritable<ServerConfig>(
    configuration.GetSection("ServerConfig"),
    "appsettings.json");

// In a service
public class MyService
{
    private readonly IWritableOptions<ServerConfig> _settings;

    public MyService(IWritableOptions<ServerConfig> settings)
    {
        _settings = settings;
    }

    public void UpdateServerPort(int newPort)
    {
        // Updates configuration and persists to appsettings.json
        _settings.Update(config => config.Port = newPort);
    }

    public int GetCurrentPort()
    {
        return _settings.Value.Port;
    }
}

Configuration File Example (appsettings.json):

{
  "ServerConfig": {
    "Name": "TemperatureController",
    "UUID": "12345678-1234-1234-1234-123456789012",
    "FQHN": "localhost",
    "Port": 50051,
    "NetworkInterface": "0.0.0.0",
    "DiscoveryServiceName": "_sila2._tcp.local."
  }
}

Writable Options Pattern

The writable options pattern extends ASP.NET Core's standard options pattern by enabling runtime updates that persist to disk.

Standard Options vs. Writable Options

Standard Options (Read-Only):

public class MyService
{
    private readonly IOptions<ServerConfig> _options;

    public MyService(IOptions<ServerConfig> options)
    {
        _options = options;
        // Can only READ configuration
        var port = _options.Value.Port;
    }
}

Writable Options (Read-Write):

public class MyService
{
    private readonly IWritableOptions<ServerConfig> _options;

    public MyService(IWritableOptions<ServerConfig> options)
    {
        _options = options;
    }

    public void UpdateConfiguration()
    {
        // Can READ configuration
        var currentPort = _options.Value.Port;

        // Can WRITE configuration (persists to appsettings.json)
        _options.Update(config =>
        {
            config.Port = 8080;
            config.FQHN = "192.168.1.100";
        });
    }
}

Complete Example

1. Define Configuration Class:

public class ServerConfig
{
    public string Name { get; set; }
    public Guid UUID { get; set; }
    public string FQHN { get; set; }
    public int Port { get; set; }
}

2. Register Writable Options:

// In Program.cs
services.ConfigureWritable<ServerConfig>(
    configuration.GetSection("ServerConfig"),
    "appsettings.json");

3. Inject and Use:

public class ServerConfigurationService
{
    private readonly IWritableOptions<ServerConfig> _config;
    private readonly ILogger<ServerConfigurationService> _logger;

    public ServerConfigurationService(
        IWritableOptions<ServerConfig> config,
        ILogger<ServerConfigurationService> logger)
    {
        _config = config;
        _logger = logger;
    }

    public void ChangeServerPort(int newPort)
    {
        _config.Update(settings =>
        {
            settings.Port = newPort;
        });

        _logger.LogInformation($"Server port updated to {newPort}");
        // appsettings.json is now updated with new port
    }
}

How It Works:

  1. Reads appsettings.json as JSON
  2. Deserializes the specified section to type T
  3. Applies your changes via the lambda
  4. Serializes back to JSON
  5. Writes to disk with indented formatting
  6. Reloads configuration so all services see updated values

Complete Server Setup Example

Using AddSiLA2Server() for a clean, production-ready setup:

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Server.Kestrel.Core;
using Microsoft.Extensions.DependencyInjection;
using SiLA2.AspNetCore;
using SiLA2.Server;
using YourFeature.Services;

var builder = WebApplication.CreateBuilder(args);

// ===== Configure Services =====
builder.Services.AddSiLA2Server(builder.Configuration, options =>
{
    options.EnableBinaryTransfer = true;
    options.EnableGrpcReflection = true;
    options.EnableDetailedErrors = true;  // Set false in production
});

// Feature services
builder.Services.AddSingleton<YourFeatureService>();
builder.Services.AddSingleton<LockControllerService>();
builder.Services.AddSingleton(sp => ActivatorUtilities.CreateInstance<AuthenticationService>(sp));

// ===== Configure Kestrel =====
// ListenSiLA2 applies the endpoint defaults, enables HTTPS when a certificate is
// present, and serves cleartext gRPC as h2c when SILA_TLS=false.
builder.WebHost.ConfigureKestrel(options =>
{
    options.ListenSiLA2(args.GetKestrelConfigData(options.ApplicationServices));
});

var app = builder.Build();

// ===== Configure Application =====
var siLA2Server = app.Services.GetRequiredService<ISiLA2Server>();
app.InitializeSiLA2Features(siLA2Server);

// Map gRPC services
app.MapGrpcService<SiLAService>();
app.MapGrpcService<YourFeatureService>();
app.MapGrpcService<LockControllerService>();
app.MapGrpcService<AuthenticationService>();

// Optional: gRPC reflection (if enabled)
app.MapGrpcReflectionService();

// Start mDNS announcement
siLA2Server.Start();

app.Run();

Advanced Setup (Fine-Grained Control)

For cases where you need precise control over service registration:

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Server.Kestrel.Core;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using SiLA2.AspNetCore;
using SiLA2.Commands;
using SiLA2.Server;
using SiLA2.Server.Services;
using SiLA2.Utils.Config;
using SiLA2.Utils.gRPC;
using SiLA2.Utils.Network;
using SiLA2.Utils.Security;
using YourFeature.Services;

var builder = WebApplication.CreateBuilder(args);

// ===== Configure Services =====
ConfigureServices(builder.Services, builder.Configuration);

// ===== Configure Kestrel =====
// ListenSiLA2 applies the endpoint defaults, enables HTTPS when a certificate is
// present, and serves cleartext gRPC as h2c when SILA_TLS=false.
builder.WebHost.ConfigureKestrel(options =>
{
    options.ListenSiLA2(args.GetKestrelConfigData(options.ApplicationServices));
});

var app = builder.Build();

// ===== Configure Application =====
ConfigureApplication(app);

app.Run();

// ===== Service Registration =====
void ConfigureServices(IServiceCollection services, IConfiguration configuration)
{
    // Use individual extension methods for granular control
    services.AddSiLA2Grpc(enableDetailedErrors: true);
    services.AddSiLA2CoreServices();
    services.AddSiLA2CertificateServices();
    services.AddSiLA2BinaryTransfer();
    services.AddSiLA2ServerConfig(configuration);

    // Feature services
    services.AddSingleton<YourFeatureService>();
    services.AddSingleton<LockControllerService>();
    services.AddSingleton(sp => ActivatorUtilities.CreateInstance<AuthenticationService>(sp));
}

// ===== Application Configuration =====
void ConfigureApplication(WebApplication app)
{
    var siLA2Server = app.Services.GetRequiredService<ISiLA2Server>();

    // Initialize features from Features/*.sila.xml
    app.InitializeSiLA2Features(siLA2Server);

    // Map gRPC services
    app.MapGrpcService<SiLAService>();
    app.MapGrpcService<YourFeatureService>();
    app.MapGrpcService<LockControllerService>();
    app.MapGrpcService<AuthenticationService>();

    // Optional: gRPC reflection for debugging
    app.MapGrpcReflectionService();

    // Start mDNS announcement
    siLA2Server.Start();
}

Command-Line Arguments

The GetKestrelConfigData() method parses command-line arguments to override server configuration.

Supported Arguments

Argument Position Description Example
1st argument IP address or FQHN 127.0.0.1 or myserver.local
2nd argument Port number 50051

Examples

# Default configuration from appsettings.json
dotnet run

# Override IP address
dotnet run -- 192.168.1.100

# Override IP and port
dotnet run -- 192.168.1.100 8080

# Use localhost
dotnet run -- 127.0.0.1 50051

Fallback Behavior

  • If no IP is provided or IP parsing fails → IPAddress.Any (0.0.0.0)
  • If no port is provided → Value from IServerConfig.Port
  • Certificate is always loaded from ICertificateProvider

SILA_* Environment Variables

Servers read their configuration from flat SILA_* environment variables in addition to appsettings.json. These are the names used by the SiLA-Box, whose box manager assigns each installed service a free SILA_PORT and forces SILA_HOST — a server that ignores them is unreachable and reported as "reachable but not a SiLA server".

AddSiLA2Server() registers the source automatically, so no code change is needed in existing servers.

Supported Variables

Variable Maps to Description
SILA_HOST ServerConfig:FQHN Interface to bind to
SILA_PORT ServerConfig:Port TCP port (0-65535)
SILA_TLS ServerConfig:Tls Enable TLS. Accepts 1/true/yes/on and 0/false/no/off
SILA_DATA_DIR ServerConfig:DataDir Directory for the server UUID and generated certificates
SILA_SERVER_NAME ServerConfig:Name Name advertised on the network
SILA_SERVER_UUID ServerConfig:UUID Stable unique identifier
SILA_SERVER_TYPE ServerInfo:Type Type identifier
SILA_SERVER_VERSION ServerInfo:Version Server version
SILA_SERVER_DESCRIPTION ServerInfo:Description Description advertised on the network
SILA_VENDOR_URL ServerInfo:VendorURI Vendor website
SILA_CERT_FILE / SILA_KEY_FILE ServerConfig:CertFile / :KeyFile Optional PEM certificate chain and private key

Names are declared once in SilaEnvironmentVariables, so referring to them from code needs no string literals.

Precedence

command line  >  SILA_*  >  ServerConfig__*  >  appsettings.json

An unset or empty variable changes nothing, so existing deployments are unaffected. docker run -e SILA_HOST= produces a present-but-empty variable, which is treated as unset rather than blanking out the configured bind address.

Invalid values fail fast at startup rather than being silently ignored — a server that quietly disregards the port it was assigned is far harder to diagnose than one that refuses to start:

System.InvalidOperationException: Environment variable 'SILA_PORT' must be between 0 and 65535, got 99999.

Manual Registration

Applications that do not use AddSiLA2Server(), or that hold a plain IConfiguration rather than a ConfigurationManager, can add the source themselves. The call is idempotent:

using SiLA2.AspNetCore.Configuration;

builder.Configuration.AddSilaEnvironmentVariables();

Persistent Identity with SILA_DATA_DIR

SiLA 2 requires a server's UUID to stay constant across restarts, and clients trust a server's self-signed certificate on first use. In a container both live on a writable volume, or they are lost whenever the container is recreated.

Setting SILA_DATA_DIR stores both there:

File Contents
server.uuid The server UUID
server.crt / server.key The generated self-signed certificate
ca.crt / ca.key The generated certificate authority
docker run -d --network host \
  -e SILA_HOST=0.0.0.0 -e SILA_PORT=40050 \
  -v my-server-data:/data \
  my-sila-server:latest

UUID Resolution Order

  1. SILA_SERVER_UUID, if set
  2. A persisted $SILA_DATA_DIR/server.uuid
  3. A newly generated UUID — only when SILA_DATA_DIR is set, then written there
  4. ServerConfig:UUID from appsettings.json, when no data directory is configured

Step 3 matters for containers: appsettings.json ships inside an image, so without it every container started from one image would advertise the same UUID and two instances on a box would be indistinguishable. Configuring a data directory is the signal that the server owns its identity there. Set SILA_SERVER_UUID to pin a specific value.

Step 4 means behaviour is unchanged for servers that do not set SILA_DATA_DIR.

An unwritable SILA_DATA_DIR is a startup error, not a warning — a container that cannot persist its identity would otherwise regenerate it on every restart and surface much later as a server that inexplicably changed UUID.



Integration with SiLA2.Utils

SiLA2.AspNetCore depends on services from SiLA2.Utils for core functionality:

Service Purpose Used By
ICertificateProvider Loads/generates TLS certificates GetKestrelConfigData()
IServerConfig Server configuration (name, UUID, port, FQHN) GetKestrelConfigData()
INetworkService Network operations (IP resolution, interface discovery) Feature services
IServiceAnnouncer mDNS service announcement ISiLA2Server.Start()

Dependency Chain:

SiLA2.AspNetCore
  └─ SiLA2.Core (SiLA2.dll)
      └─ SiLA2.Utils
          ├─ Security (ICertificateProvider)
          ├─ Config (IServerConfig)
          └─ Network (INetworkService, mDNS)

Example: Certificate Provider Registration:

// Register certificate provider
services.AddSingleton<ICertificateProvider, CertificateProvider>();
services.AddSingleton<ICertificateContext, CertificateContext>();
services.AddSingleton<ICertificateRepository, CertificateRepository>();

// Kestrel will automatically use the provider
builder.WebHost.ConfigureKestrel(options =>
{
    var (_, _, certificate) = args.GetKestrelConfigData(options.ApplicationServices);
    // certificate is loaded from ICertificateProvider
});

Working Examples

Explore complete working examples in the repository:

Temperature Controller Example

Path: src/Examples/TemperatureController/SiLA2.Temperature.Server.App/

Features:

  • Complete ASP.NET Core setup with InitializeSiLA2Features()
  • Kestrel configuration with command-line argument parsing
  • Writable options for server configuration
  • gRPC interceptors for validation and logging
  • mDNS service announcement

Run:

cd src/Examples/TemperatureController/SiLA2.Temperature.Server.App
dotnet run

# With custom IP/port:
dotnet run -- 127.0.0.1 50051

Shaker Controller Example

Path: src/Examples/ShakerController/SiLA2.Shaker.Server.App/

Run:

cd src/Examples/ShakerController/SiLA2.Shaker.Server.App
dotnet run

Other Examples

  • Data Type Provider: src/Examples/DataTypeProvider/
  • Web Frontend Server: src/Examples/TemperatureController/SiLA2.Temperature.Server.App.Webfrontend/

Best Practices

1. Initialization Order

Always follow this sequence:

var app = builder.Build();                        // 1. Build host
app.InitializeSiLA2Features(siLA2Server);         // 2. Load .sila.xml files
app.MapGrpcService<MyFeatureService>();           // 3. Map gRPC endpoints
siLA2Server.Start();                              // 4. Announce via mDNS
app.Run();                                        // 5. Start server

2. Writable Options for Server Settings

Use writable options for configuration that needs runtime updates:

services.ConfigureWritable<ServerConfig>(
    configuration.GetSection("ServerConfig"),
    "appsettings.json");

3. Use AddSiLA2Server() for New Projects

// Recommended: registers all services with correct lifetimes
builder.Services.AddSiLA2Server(builder.Configuration);

// Only use individual methods if you need fine-grained control
services.AddSiLA2CoreServices();
services.AddSiLA2CertificateServices();

4. Enable Detailed Errors in Development

services.AddGrpc(options =>
{
    options.EnableDetailedErrors = true;  // Debug mode only
});

5. Use gRPC Interceptors

Add validation and logging interceptors:

services.AddGrpc(options =>
{
    options.Interceptors.Add<LoggingInterceptor>();
    options.Interceptors.Add<MetadataValidationInterceptor>();
    options.Interceptors.Add<ParameterValidationInterceptor>();
});

6. Feature Directory Structure

Place .sila.xml files in Features/ directory:

MyServer.App/
├── Features/
│   ├── MyFeature-v1_0.sila.xml      ← Feature definitions
│   └── AnotherFeature-v1_0.sila.xml
├── Services/
│   └── MyFeatureService.cs          ← Service implementations
└── Program.cs

7. Certificate Handling

Let ICertificateProvider manage certificates automatically:

services.AddSingleton<ICertificateProvider, CertificateProvider>();
// Automatically generates self-signed cert if none exists

8. Development vs. Production Configuration

Use different appsettings files:

#if DEBUG
    var configFile = "appsettings.Development.json";
#else
    var configFile = "appsettings.json";
#endif

services.ConfigureWritable<ServerConfig>(
    configuration.GetSection("ServerConfig"),
    configFile);

Additional Resources


Contribution

It's Open Source (License: MIT). Feel free to use or contribute!

Repository: https://gitlab.com/SiLA2/sila_csharp

Maintainer: Christoph Pohl (@Chamundi)

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
10.3.3 209 10/6/2026
10.3.2 141 9/27/2026
10.3.1 129 9/26/2026
10.3.0 710 7/26/2026
10.2.6 508 7/5/2026
10.2.5 149 7/4/2026
10.2.4 1,499 3/13/2026
10.2.3 186 3/7/2026
10.2.2 874 2/12/2026
10.2.1 360 1/25/2026
10.2.0 492 12/23/2025
10.1.0 438 11/29/2025
10.0.0 448 11/11/2025
9.0.4 563 6/25/2025
9.0.3 264 6/21/2025
9.0.2 725 1/6/2025
9.0.1 357 11/17/2024
9.0.0 271 11/13/2024
8.1.2 417 10/20/2024
8.1.1 844 8/31/2024
Loading failed