SiLA2.Utils 10.2.2

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

SiLA2.Utils

Utility Library for SiLA2 .NET Implementation

NuGet Package SiLA2.Utils on NuGet.org
Repository https://gitlab.com/SiLA2/sila_csharp
SiLA Standard https://sila-standard.com
License MIT

Introduction

SiLA2.Utils is the foundational utility library for the SiLA2 .NET implementation, providing essential infrastructure components for building SiLA2-compliant laboratory automation systems. This library handles network discovery, security, gRPC channel management, and other cross-cutting concerns required by both SiLA2 servers and clients.

The library is platform-independent and targets .NET 10, making it suitable for deployment on Windows, Linux, and macOS environments including embedded systems.

Key Features

  • DNS/mDNS Service Discovery - RFC 6763 compliant DNS-SD implementation for automatic discovery of SiLA2 servers on local networks
  • Security & Certificate Management - X.509 certificate generation, validation, and management with SiLA2-specific extensions
  • gRPC Channel Providers - Simplified gRPC channel creation with TLS/SSL configuration and connection pooling
  • Command-Line Argument Parsing - Standardized argument handling for server and client applications
  • Network Utilities - Network interface detection, service profiles, and IP address management
  • Extension Methods - Helpful extensions for reflection, unit conversion, dynamic objects, and ZIP handling

Relationship to SiLA2.Core

SiLA2.Utils is a dependency of SiLA2.Core (the main SiLA2 server library) and can be used independently when building custom SiLA2 clients or when you need just the utility functionality without the full server implementation.

Installation

Install via NuGet Package Manager:

dotnet add package SiLA2.Utils

Or via Package Manager Console:

Install-Package SiLA2.Utils

Core Components

1. DNS/mDNS Service Discovery

The library provides a complete implementation of DNS-based Service Discovery (RFC 6763) using multicast DNS for automatic discovery of SiLA2 servers on local networks.

Key Classes:

  • ServiceDiscovery - High-level service discovery and advertisement
  • MulticastService - Low-level multicast DNS communication
  • ServiceProfile - Service metadata and resource records

Example: Discovering SiLA2 Servers

using SiLA2.Utils.Network.mDNS;
using Microsoft.Extensions.Logging;

// Create logger
var loggerFactory = LoggerFactory.Create(builder => builder.AddConsole());
var logger = loggerFactory.CreateLogger<ServiceDiscovery>();

// Initialize service discovery
var discovery = new ServiceDiscovery(logger);

// Subscribe to service discovery events
discovery.ServiceInstanceDiscovered += (sender, args) =>
{
    Console.WriteLine($"Discovered service: {args.ServiceInstanceName}");

    // Extract service details from DNS message
    foreach (var record in args.Message.AdditionalRecords)
    {
        if (record is SRVRecord srv)
        {
            Console.WriteLine($"  Host: {srv.Target}, Port: {srv.Port}");
        }
        else if (record is TXTRecord txt)
        {
            Console.WriteLine($"  Properties: {string.Join(", ", txt.Strings)}");
        }
    }
};

// Start listening for mDNS announcements
discovery.Mdns.Start();

// Query for SiLA2 services (typically "_sila2._tcp")
discovery.QueryServiceInstances("_sila2._tcp");

// Keep listening
Console.WriteLine("Listening for SiLA2 servers. Press Enter to stop...");
Console.ReadLine();

discovery.Dispose();

Example: Advertising a SiLA2 Server

using SiLA2.Utils.Network.mDNS;
using SiLA2.Utils.Network.Dns;
using System.Net;

var logger = loggerFactory.CreateLogger<ServiceDiscovery>();
var discovery = new ServiceDiscovery(logger);

// Create service profile
var profile = new ServiceProfile(
    instanceName: "MyTemperatureController",      // Unique instance name
    serviceName: "_sila2._tcp",                    // Service type
    port: 50051,                                   // gRPC port
    addresses: new[] { IPAddress.Parse("192.168.1.100") }
);

// Add custom properties (visible to clients)
profile.AddProperty("ServerUUID", Guid.NewGuid().ToString());
profile.AddProperty("ServerName", "Temperature Controller v1.0");
profile.AddProperty("ServerType", "SiLA2");

// Start advertising
discovery.Mdns.Start();
discovery.Advertise(profile);

// Send announcement
discovery.Announce(profile);

Console.WriteLine("Service advertised. Press Enter to stop...");
Console.ReadLine();

// Cleanup: send goodbye message
discovery.Unadvertise(profile);
discovery.Dispose();

2. Security & Certificate Management

The library provides comprehensive X.509 certificate management specifically designed for SiLA2's security requirements, including embedding server UUIDs in certificate extensions.

Key Classes:

  • ICertificateProvider / CertificateProvider - Certificate generation and management
  • ICertificateRepository / CertificateRepository - Certificate storage and retrieval
  • ICertificateContext - Certificate configuration context

Example: Creating Server Certificates

using SiLA2.Utils.Security;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using System.Security.Cryptography;

// Setup dependencies (typically from DI container)
var configuration = new ConfigurationBuilder()
    .AddInMemoryCollection(new Dictionary<string, string>
    {
        ["ServerConfig:UUID"] = Guid.NewGuid().ToString()
    })
    .Build();

var logger = loggerFactory.CreateLogger<ICertificateProvider>();
var certificateRepository = new CertificateRepository(configuration, logger);
var certificateProvider = new CertificateProvider(certificateRepository, configuration, logger);

// Generate a self-signed server certificate
var serverUuid = Guid.Parse(configuration["ServerConfig:UUID"]);
using var key = RSA.Create(2048);

var certificate = certificateProvider.CreateServerCertificate(
    baseCertificate: null,        // null = self-signed
    key: key,
    serverGuid: serverUuid
);

Console.WriteLine($"Certificate Subject: {certificate.Subject}");
Console.WriteLine($"Valid From: {certificate.NotBefore}");
Console.WriteLine($"Valid To: {certificate.NotAfter}");
Console.WriteLine($"Thumbprint: {certificate.Thumbprint}");

// The certificate includes:
// - TLS Server Authentication
// - TLS Client Authentication
// - Server UUID in extension (OID 1.3.6.1.4.1.58583)
// - Subject Alternative Names (SANs) for all network interfaces

Example: Creating a Certificate Authority and Signed Certificate

// Create root CA certificate
using var caKey = RSA.Create(4096);
var caCertificate = certificateProvider.CreateRootCertificate(caKey);

Console.WriteLine($"CA Certificate: {caCertificate.Subject}");

// Create server certificate signed by CA
using var serverKey = RSA.Create(2048);
var signedCertificate = certificateProvider.CreateServerCertificate(
    baseCertificate: caCertificate.CopyWithPrivateKey(caKey),
    key: serverKey,
    serverGuid: Guid.NewGuid()
);

Console.WriteLine($"Server Certificate: {signedCertificate.Subject}");
Console.WriteLine($"Issuer: {signedCertificate.Issuer}");

// Verify certificate chain
using var chain = new X509Chain();
chain.ChainPolicy.TrustMode = X509ChainTrustMode.CustomRootTrust;
chain.ChainPolicy.CustomTrustStore.Add(caCertificate);
chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;

bool isValid = chain.Build(signedCertificate);
Console.WriteLine($"Certificate chain valid: {isValid}");

3. gRPC Channel Management

The GrpcChannelProvider simplifies secure gRPC channel creation with automatic certificate validation, connection pooling, and custom CA support.

Key Classes:

  • IGrpcChannelProvider / GrpcChannelProvider - gRPC channel factory with security

Example: Creating Secure gRPC Channels

using SiLA2.Utils.gRPC;
using Grpc.Net.Client;
using System.Security.Cryptography.X509Certificates;

var logger = loggerFactory.CreateLogger<GrpcChannelProvider>();
var channelProvider = new GrpcChannelProvider(logger);

// Load CA certificate for validation
var caCertificate = new X509Certificate2("ca-certificate.pem");

// Create secure channel with custom CA validation
var channel = await channelProvider.GetChannel(
    host: "192.168.1.100",
    port: 50051,
    acceptAnyServerCertificate: false,  // Enforce validation
    ca: caCertificate,
    channelOptions: null  // Use defaults
);

// Use channel with any gRPC client
// var client = new MyService.MyServiceClient(channel);
// var response = await client.MyMethodAsync(new Request());

Console.WriteLine($"Channel created: {channel.Target}");
Console.WriteLine($"Channel state: {channel.State}");

Example: Quick Setup for Development (Accept Any Certificate)

// WARNING: Only use this for development/testing!
var channel = await channelProvider.GetChannel(
    host: "localhost",
    port: 50051,
    acceptAnyServerCertificate: true  // Skip certificate validation
);

// Channel is ready to use
Console.WriteLine($"Development channel: {channel.Target}");

Connection Pooling:

The GrpcChannelProvider automatically pools channels by host:port combination. Multiple calls with the same parameters return the same channel instance, enabling efficient connection reuse across multiple client instances.

4. Command-Line Argument Parsing

Standardized command-line argument parsing for SiLA2 server and client applications using the CommandLineParser library.

Key Classes:

  • CmdLineServerArgs - Server startup arguments
  • CmdLineClientArgs - Client connection arguments

Example: Server Argument Parsing

using SiLA2.Utils.CmdArgs.Server;
using CommandLine;

class Program
{
    static void Main(string[] args)
    {
        Parser.Default.ParseArguments<CmdLineServerArgs>(args)
            .WithParsed(options =>
            {
                Console.WriteLine($"Server UUID: {options.Id}");
                Console.WriteLine($"Host: {options.Fqhn}");
                Console.WriteLine($"Port: {options.Port}");
                Console.WriteLine($"Network Interface: {options.Nic}");
                Console.WriteLine($"mDNS Suffix: {options.MdnsSuffix}");

                if (options.ListInterfaces)
                {
                    Console.WriteLine("\nAvailable Network Interfaces:");
                    foreach (var nic in NetworkInterface.GetAllNetworkInterfaces())
                    {
                        Console.WriteLine($"  {nic.Name} ({nic.OperationalStatus})");
                    }
                    return;
                }

                if (options.ShowVersion)
                {
                    Console.WriteLine($"SiLA2.Utils version: {typeof(CmdLineServerArgs).Assembly.GetName().Version}");
                    return;
                }

                // Start server with parsed options...
            })
            .WithNotParsed(errors =>
            {
                Console.WriteLine("Failed to parse arguments.");
            });
    }
}

Typical Server Command Line:

dotnet run --project MyServer.App -- -g "550e8400-e29b-41d4-a716-446655440000" -n "192.168.1.100" -p 50051 -i "eth0" -m ".local"

Supported Arguments:

Argument Short Long Description
UUID -g --guid Server unique identifier (GUID format)
Host -n --fqhn IP address, CIDR, or fully qualified host name
Port -p --port TCP port for gRPC server (default: 50051)
NIC -i --nic Network interface for mDNS (name, IP, or CIDR)
mDNS Suffix -m --mdnsSuffix Domain suffix for service discovery (e.g., ".local")
List Interfaces -l --list-interfaces Display available network interfaces and exit
Version -v --version Show SiLA2 library version and exit

5. Network Utilities

Key Classes:

  • NetworkService / INetworkService - Network interface and IP address detection
  • MulticastService.GetNetworkInterfaces() - Static helper for network enumeration
  • MulticastService.GetIPAddresses() - Get all IP addresses of local machine
  • MulticastService.GetLinkLocalAddresses() - Get link-local addresses (IPv4 and IPv6)

Example: Network Interface Detection

using SiLA2.Utils.Network.mDNS;
using System.Net.NetworkInformation;

// Get operational network interfaces (excludes loopback unless it's the only one)
var nics = MulticastService.GetNetworkInterfaces();

Console.WriteLine("Operational Network Interfaces:");
foreach (var nic in nics)
{
    Console.WriteLine($"\n{nic.Name} ({nic.NetworkInterfaceType})");
    Console.WriteLine($"  Status: {nic.OperationalStatus}");
    Console.WriteLine($"  Speed: {nic.Speed / 1_000_000} Mbps");

    var ipProps = nic.GetIPProperties();
    foreach (var addr in ipProps.UnicastAddresses)
    {
        Console.WriteLine($"  IP: {addr.Address}");
    }
}

// Get all IP addresses (excluding loopback)
var addresses = MulticastService.GetIPAddresses();
Console.WriteLine("\nAll IP Addresses:");
foreach (var addr in addresses)
{
    Console.WriteLine($"  {addr}");
}

// Get link-local addresses suitable for mDNS
var linkLocalAddresses = MulticastService.GetLinkLocalAddresses();
Console.WriteLine("\nLink-Local Addresses (for mDNS):");
foreach (var addr in linkLocalAddresses)
{
    Console.WriteLine($"  {addr}");
}

6. Extension Methods

The library provides several extension method classes for common operations.

Available Extensions:

  • ReflectionExtensions - Reflection utilities (e.g., IsAwaitableMethod())
  • UnitConverterExtensions - Temperature unit conversions
  • DynamicExtensions - Dynamic object manipulation helpers
  • ZipExtensions - ZIP archive handling utilities
  • CertificateExtensions - X.509 certificate helper methods
  • CmdLineArgExtensions - Command-line argument processing

Example: Unit Conversion Extensions

using SiLA2.Utils.Extensions;

double tempKelvin = 298.15;

// Convert Kelvin to Celsius
double tempCelsius = tempKelvin.Kelvin2DegreeCelsius();
Console.WriteLine($"{tempKelvin} K = {tempCelsius} °C");

// Convert Celsius back to Kelvin
double tempKelvin2 = tempCelsius.DegreeCelsius2Kelvin();
Console.WriteLine($"{tempCelsius} °C = {tempKelvin2} K");

// Convert to Fahrenheit
double tempFahrenheit = tempKelvin.Kelvin2DegreeFahrenheit();
Console.WriteLine($"{tempKelvin} K = {tempFahrenheit} °F");

Example: Reflection Extensions

using SiLA2.Utils.Extensions;
using System.Reflection;

var method = typeof(MyClass).GetMethod("MyAsyncMethod");

if (method.IsAwaitableMethod())
{
    Console.WriteLine("Method returns an awaitable type (Task, Task<T>, ValueTask, etc.)");
    // Can be used with async/await
}
else
{
    Console.WriteLine("Method is synchronous");
}

API Overview

Service Discovery Interfaces

namespace SiLA2.Utils.Network.mDNS
{
    // Main service discovery facade
    public interface IServiceDiscovery : IDisposable
    {
        MulticastService Mdns { get; }
        NameServer NameServer { get; }

        event EventHandler<DomainName> ServiceDiscovered;
        event EventHandler<ServiceInstanceDiscoveryEventArgs> ServiceInstanceDiscovered;
        event EventHandler<ServiceInstanceShutdownEventArgs> ServiceInstanceShutdown;

        void QueryAllServices();
        void QueryServiceInstances(DomainName service);
        void Advertise(ServiceProfile service);
        void Announce(ServiceProfile profile);
        void Unadvertise(ServiceProfile profile);
    }

    // Low-level multicast DNS
    public interface IMulticastService : IResolver, IDisposable
    {
        event EventHandler<MessageEventArgs> QueryReceived;
        event EventHandler<MessageEventArgs> AnswerReceived;
        event EventHandler<NetworkInterfaceEventArgs> NetworkInterfaceDiscovered;

        void Start();
        void Stop();
        void SendQuery(DomainName name, DnsClass klass = DnsClass.IN, DnsType type = DnsType.ANY);
        void SendAnswer(Message answer, bool checkDuplicate = true);
    }
}

Security Interfaces

namespace SiLA2.Utils.Security
{
    public interface ICertificateProvider
    {
        X509Certificate2 CreateRootCertificate(RSA key);
        X509Certificate2 CreateServerCertificate(X509Certificate2 baseCertificate, RSA key, Guid? serverGuid);
        X509Certificate2 GetServerCertificate(bool safeIfNotExists);
        X509Certificate2 GetServerCertificate(ICertificateContext context, Guid? serverUuid, out RSA key);
        X509Certificate2 LoadCertificateFromPem(string certificate);
    }

    public interface ICertificateRepository
    {
        bool HasCertificate { get; }
        bool HasCertificateAuthority { get; }
        X509Certificate2 ServerCertificate { get; }
        ICertificateContext CertificateContext { get; }

        Task SaveCertificate(X509Certificate2 certificate, RSA key);
        Task SaveCertificateAuthority(X509Certificate2 ca, RSA key);
    }
}

gRPC Channel Interface

namespace SiLA2.Utils.gRPC
{
    public interface IGrpcChannelProvider
    {
        Task<GrpcChannel> GetChannel(
            string host,
            int port,
            bool acceptAnyServerCertificate = false,
            X509Certificate2 ca = null,
            GrpcChannelOptions channelOptions = null);
    }
}

Dependencies

SiLA2.Utils has the following NuGet dependencies:

Package Version Purpose
CommandLineParser 2.9.1 Command-line argument parsing
Grpc.Net.Client 2.76.0 gRPC client infrastructure
IPNetwork2 3.4.853 IP network and CIDR manipulation
Microsoft.Extensions.Configuration.Abstractions 10.0.2 Configuration abstractions
Microsoft.Extensions.Logging.Abstractions 10.0.2 Logging abstractions
Microsoft.Extensions.Options.ConfigurationExtensions 10.0.2 Options pattern support
SimpleBase 5.6.0 Base encoding/decoding utilities
Tmds.LibC 0.5.0 Low-level Linux system calls (cross-platform)

Platform Support

  • Target Framework: .NET 10.0
  • Operating Systems: Windows, Linux, macOS
  • Architecture: Platform-independent (AnyCPU)
  • Embedded Systems: Fully supported (library designed for embedded Linux deployment)

Integration with SiLA2.Core

When using SiLA2.Core for building SiLA2 servers, SiLA2.Utils is automatically included as a dependency. You typically interact with these utilities through the ISiLA2Server interface and dependency injection:

// In Program.cs or Startup.cs
builder.Services.AddSingleton<ICertificateProvider, CertificateProvider>();
builder.Services.AddSingleton<ICertificateRepository, CertificateRepository>();
builder.Services.AddSingleton<IGrpcChannelProvider, GrpcChannelProvider>();
builder.Services.AddSingleton<IServiceDiscovery, ServiceDiscovery>();

// These are then injected into your services
public class MyFeatureService : MyFeature.MyFeatureBase
{
    private readonly IGrpcChannelProvider _channelProvider;

    public MyFeatureService(IGrpcChannelProvider channelProvider)
    {
        _channelProvider = channelProvider;
    }
}

Advanced Usage

Custom Network Interface Filtering

Control which network interfaces are used for mDNS:

var logger = loggerFactory.CreateLogger<MulticastService>();

// Create MulticastService with custom filter
var mdns = new MulticastService(logger, nics =>
{
    // Only use Ethernet interfaces
    return nics.Where(nic => nic.NetworkInterfaceType == NetworkInterfaceType.Ethernet);
});

var discovery = new ServiceDiscovery(logger, mdns);
discovery.Mdns.Start();

Custom Certificate Validation

Implement custom certificate validation logic:

var channelOptions = new GrpcChannelOptions
{
    HttpHandler = new HttpClientHandler
    {
        ServerCertificateCustomValidationCallback = (request, cert, chain, errors) =>
        {
            // Custom validation logic
            Console.WriteLine($"Validating certificate: {cert.Subject}");

            // Check for SiLA2 server UUID extension
            var uuidExtension = cert.Extensions["1.3.6.1.4.1.58583"];
            if (uuidExtension != null)
            {
                var serverUuid = Encoding.ASCII.GetString(uuidExtension.RawData);
                Console.WriteLine($"Server UUID: {serverUuid}");
            }

            return errors == SslPolicyErrors.None;
        }
    }
};

var channel = await channelProvider.GetChannel(
    "localhost",
    50051,
    channelOptions: channelOptions
);

Service Profile with Subtypes

Advertise services with feature subtypes (RFC 6763 Section 7.1):

var profile = new ServiceProfile(
    instanceName: "AdvancedController",
    serviceName: "_sila2._tcp",
    port: 50051
);

// Add feature subtypes
profile.Subtypes.Add("temperature");
profile.Subtypes.Add("pressure");
profile.Subtypes.Add("humidity");

// Clients can query specifically for controllers with temperature support:
// discovery.QueryServiceInstances("_sila2._tcp", "temperature");

discovery.Advertise(profile);

Common Patterns

Pattern: Automatic Server Discovery and Connection

using SiLA2.Utils.Network.mDNS;
using SiLA2.Utils.gRPC;
using System.Collections.Concurrent;

var logger = loggerFactory.CreateLogger<ServiceDiscovery>();
var discovery = new ServiceDiscovery(logger);
var channelProvider = new GrpcChannelProvider(loggerFactory.CreateLogger<GrpcChannelProvider>());

var discoveredServers = new ConcurrentDictionary<string, (string host, int port)>();

discovery.ServiceInstanceDiscovered += async (sender, args) =>
{
    string? host = null;
    int port = 0;

    // Extract connection details
    foreach (var record in args.Message.AdditionalRecords)
    {
        if (record is SRVRecord srv)
        {
            host = srv.Target.ToString().TrimEnd('.');
            port = srv.Port;
        }
    }

    if (host != null && port > 0)
    {
        var serverKey = $"{host}:{port}";
        if (discoveredServers.TryAdd(serverKey, (host, port)))
        {
            Console.WriteLine($"Connecting to {serverKey}...");

            try
            {
                var channel = await channelProvider.GetChannel(
                    host,
                    port,
                    acceptAnyServerCertificate: true  // Or use proper CA
                );

                Console.WriteLine($"Connected to {serverKey}");
                // Use channel for gRPC calls...
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Failed to connect to {serverKey}: {ex.Message}");
            }
        }
    }
};

discovery.Mdns.Start();
discovery.QueryServiceInstances("_sila2._tcp");

// Keep listening for new services...
await Task.Delay(TimeSpan.FromSeconds(30));

Pattern: Server with Persistent Certificate

using SiLA2.Utils.Security;
using Microsoft.Extensions.Configuration;

var configuration = new ConfigurationBuilder()
    .AddJsonFile("appsettings.json")
    .Build();

var certificateRepository = new CertificateRepository(configuration, logger);
var certificateProvider = new CertificateProvider(certificateRepository, configuration, logger);

// Get or create certificate (persisted to disk)
var serverCertificate = certificateProvider.GetServerCertificate(safeIfNotExists: true);

Console.WriteLine($"Using certificate: {serverCertificate.Thumbprint}");
Console.WriteLine($"Valid until: {serverCertificate.NotAfter}");

// Use certificate for HTTPS/gRPC server configuration...

Troubleshooting

Issue: mDNS Discovery Not Working

Check network interfaces:

dotnet run -- --list-interfaces

Verify firewall allows UDP port 5353 (mDNS):

# Linux
sudo ufw allow 5353/udp

# Windows (PowerShell as Admin)
New-NetFirewallRule -DisplayName "mDNS" -Direction Inbound -Protocol UDP -LocalPort 5353 -Action Allow

Explicitly specify network interface:

dotnet run -- -i "eth0"  # Or specific IP like "192.168.1.0/24"

Issue: Certificate Validation Failures

Check certificate details:

Console.WriteLine($"Subject: {certificate.Subject}");
Console.WriteLine($"Issuer: {certificate.Issuer}");
Console.WriteLine($"Valid From: {certificate.NotBefore}");
Console.WriteLine($"Valid To: {certificate.NotAfter}");
Console.WriteLine($"Has Private Key: {certificate.HasPrivateKey}");

// Check SANs
var sanExtension = certificate.Extensions
    .OfType<X509Extension>()
    .FirstOrDefault(ext => ext.Oid.Value == "2.5.29.17");

if (sanExtension != null)
{
    Console.WriteLine($"SANs: {sanExtension}");
}

Enable detailed gRPC logging:

var loggerFactory = LoggerFactory.Create(builder =>
{
    builder.SetMinimumLevel(LogLevel.Debug);
    builder.AddConsole();
});

Issue: Connection Refused / Port Already in Use

Check if port is available:

# Linux/macOS
netstat -tuln | grep 50051

# Windows
netstat -ano | findstr 50051

Use different port:

dotnet run -- -p 50052

Contributing

This library is part of the SiLA2 C# implementation. Contributions are welcome!

  1. Fork the repository
  2. Create a feature branch
  3. Make your changes
  4. Submit a merge request

For issues and feature requests, visit: https://gitlab.com/SiLA2/sila_csharp/-/issues

License

This project is licensed under the MIT License. See the repository for details.

Additional Resources


Version: 10.0.0 Maintainer: Ch@mundi Company: SiLA Consortium

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

Showing the top 2 NuGet packages that depend on SiLA2.Utils:

Package Downloads
SiLA2.Core

.NET 10 Server Implementation of the SiLA2 Standard (https://sila-standard.com/)

SiLA2.Authentication

Authentication and User Management library for SiLA2 with database-agnostic abstractions and SQLite default implementation.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
10.2.2 230 2/12/2026
10.2.1 327 1/25/2026
10.2.0 521 12/23/2025
10.1.0 458 11/29/2025
10.0.0 470 11/11/2025
9.0.4 590 6/25/2025
9.0.3 309 6/21/2025
9.0.2 602 1/6/2025
9.0.1 297 11/17/2024
9.0.0 281 11/13/2024
8.1.2 637 10/20/2024
8.1.1 967 8/31/2024
8.1.0 1,289 2/11/2024
8.0.0 905 11/15/2023
7.5.4 2,329 10/27/2023
7.5.3 822 7/19/2023
7.5.2 894 7/3/2023
7.5.1 560 6/2/2023
7.4.6 853 5/21/2023
7.4.5 646 5/7/2023
Loading failed