SiLA2.AspNetCore 10.2.2

dotnet add package SiLA2.AspNetCore --version 10.2.2
                    
NuGet\Install-Package SiLA2.AspNetCore -Version 10.2.2
                    
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.2.2" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="SiLA2.AspNetCore" Version="10.2.2" />
                    
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.2.2
                    
#r "nuget: SiLA2.AspNetCore, 10.2.2"
                    
#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.2.2
                    
#: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.2.2
                    
Install as a Cake Addin
#tool nuget:?package=SiLA2.AspNetCore&version=10.2.2
                    
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

  • Extension Methods for Dependency Injection - Streamlined service registration for SiLA2 components
  • Kestrel Server Configuration - Automatic TLS/SSL certificate handling with GetKestrelConfigData()
  • 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:

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

var builder = WebApplication.CreateBuilder(args);

// Register SiLA2 services
builder.Services.AddGrpc();
builder.Services.AddSingleton<ISiLA2Server, SiLA2Server>();
builder.Services.AddSingleton<ICertificateProvider, CertificateProvider>();
builder.Services.AddSingleton<IServerConfig>(new ServerConfig(
    name: "MyDevice",
    uuid: Guid.NewGuid(),
    fqhn: "localhost",
    port: 50051));

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

// Configure Kestrel with automatic certificate handling
builder.WebHost.ConfigureKestrel(options =>
{
    var (ipAddress, port, certificate) = args.GetKestrelConfigData(
        options.ApplicationServices);
    options.ConfigureEndpointDefaults(
        endpoints => endpoints.Protocols = HttpProtocols.Http1AndHttp2);
    options.Listen(ipAddress, port,
        listenOptions => listenOptions.UseHttps(certificate));
});

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();

Run the server:

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

Extension Methods

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

Example:

builder.WebHost.ConfigureKestrel(options =>
{
    var (ipAddress, port, certificate) = args.GetKestrelConfigData(
        options.ApplicationServices);

    options.Listen(ipAddress, port, listenOptions =>
    {
        listenOptions.UseHttps(certificate);
    });
});

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

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

Here's a production-ready SiLA2 server template:

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 =====
builder.WebHost.ConfigureKestrel(options =>
{
    var (ipAddress, port, certificate) = args.GetKestrelConfigData(
        options.ApplicationServices);

    options.ConfigureEndpointDefaults(
        endpoints => endpoints.Protocols = HttpProtocols.Http1AndHttp2);

    options.Listen(ipAddress, port, listenOptions =>
    {
        listenOptions.UseHttps(certificate);
    });
});

var app = builder.Build();

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

app.Run();

// ===== Service Registration =====
void ConfigureServices(IServiceCollection services, IConfiguration configuration)
{
    // gRPC configuration
    services.AddGrpc(options =>
    {
        options.EnableDetailedErrors = true;
        options.Interceptors.Add<SiLA2.Server.Interceptors.LoggingInterceptor>();
        options.Interceptors.Add<SiLA2.Server.Interceptors.MetadataValidationInterceptor>();
        options.Interceptors.Add<SiLA2.Server.Interceptors.ParameterValidationInterceptor>();
    });

    // Core SiLA2 services
    services.AddSingleton<ISiLA2Server, SiLA2Server>();
    services.AddSingleton<IGrpcChannelProvider, GrpcChannelProvider>();
    services.AddSingleton(typeof(IObservableCommandManager<,>),
        typeof(ObservableCommandManager<,>));

    // Security and networking
    services.AddSingleton<ICertificateProvider, CertificateProvider>();
    services.AddSingleton<ICertificateContext, CertificateContext>();
    services.AddTransient<INetworkService, NetworkService>();

    // Server configuration
    var serverConfig = new ServerConfig(
        name: configuration["ServerConfig:Name"],
        uuid: Guid.Parse(configuration["ServerConfig:UUID"]),
        fqhn: configuration["ServerConfig:FQHN"],
        port: int.Parse(configuration["ServerConfig:Port"]),
        networkInterface: configuration["ServerConfig:NetworkInterface"],
        discoveryServiceName: configuration["ServerConfig:DiscoveryServiceName"]);
    services.AddSingleton<IServerConfig>(serverConfig);

    // Writable options for runtime configuration updates
    services.ConfigureWritable<ServerConfig>(
        configuration.GetSection("ServerConfig"),
        "appsettings.json");

    // Feature services
    services.AddSingleton<YourFeatureService>();
    services.AddSingleton<LockControllerService>();
    services.AddSingleton<AuthenticationService>();
}

// ===== 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

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. Register ISiLA2Server as Singleton

services.AddSingleton<ISiLA2Server, SiLA2Server>();
// NOT AddScoped or AddTransient

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.2.2 154 2/12/2026
10.2.1 266 1/25/2026
10.2.0 429 12/23/2025
10.1.0 380 11/29/2025
10.0.0 385 11/11/2025
9.0.4 498 6/25/2025
9.0.3 214 6/21/2025
9.0.2 667 1/6/2025
9.0.1 305 11/17/2024
9.0.0 217 11/13/2024
8.1.2 351 10/20/2024
8.1.1 756 8/31/2024
8.1.0 861 2/11/2024
8.0.0 862 11/15/2023
7.5.4 2,068 10/27/2023
7.5.3 667 7/19/2023
7.5.2 437 7/3/2023
7.5.1 478 6/2/2023
7.4.6 398 5/21/2023
7.4.5 391 5/7/2023
Loading failed