![]() |
VOOZH | about |
dotnet add package SiLA2.Communication --version 10.2.4
NuGet\Install-Package SiLA2.Communication -Version 10.2.4
<PackageReference Include="SiLA2.Communication" Version="10.2.4" />
<PackageVersion Include="SiLA2.Communication" Version="10.2.4" />Directory.Packages.props
<PackageReference Include="SiLA2.Communication" />Project file
paket add SiLA2.Communication --version 10.2.4
#r "nuget: SiLA2.Communication, 10.2.4"
#:package SiLA2.Communication@10.2.4
#addin nuget:?package=SiLA2.Communication&version=10.2.4Install as a Cake Addin
#tool nuget:?package=SiLA2.Communication&version=10.2.4Install as a Cake Tool
Runtime Dynamic Protobuf Generation for SiLA2 Features
| NuGet Package | SiLA2.Communication on NuGet.org |
| Repository | https://gitlab.com/SiLA2/sila_csharp |
| SiLA Standard | https://sila-standard.com |
| License | MIT |
SiLA2.Communication is a specialized component of the sila_csharp implementation that enables dynamic gRPC communication with SiLA2 servers using runtime-generated protobuf types. This eliminates the need for compile-time code generation when working with SiLA2 Feature Definition Language (FDL) files.
Standard Approach (Compile-time):
.sila.xml (FDL) → XSLT → .proto → protoc → C# gRPC stubs → Compiled Assembly
Dynamic Approach (Runtime):
.sila.xml (FDL) → Runtime IL Emission → Dynamic Types → Reflection-based gRPC calls
This package is ideal for:
| Scenario | Use SiLA2.Communication | Use Standard Approach |
|---|---|---|
| Building a universal SiLA2 client | ✅ Yes | ❌ No |
| Runtime feature loading | ✅ Yes | ❌ No |
| Testing multiple features | ✅ Yes | ⚠️ Optional |
| Production feature implementation | ⚠️ Optional | ✅ Yes (better performance) |
| Static feature set known at compile time | ❌ No | ✅ Yes |
Install via NuGet Package Manager:
dotnet add package SiLA2.Communication
Or via Package Manager Console:
Install-Package SiLA2.Communication
| Target Framework | Supported |
|---|---|
| .NET 10.0+ | Yes (full feature support) |
| .NET Standard 2.0 | Yes |
| .NET Framework 4.6.1+ | Yes (via netstandard2.0) |
| .NET Core 2.0+ | Yes (via netstandard2.0) |
| Mono 5.4+ | Yes (via netstandard2.0) |
| Xamarin | Yes (via netstandard2.0) |
This package multi-targets net10.0 and netstandard2.0, allowing it to be used from both modern .NET and legacy .NET Framework projects.
SiLA2 features are defined in XML files following the SiLA2 FDL schema. This package analyzes FDL metadata at runtime to generate corresponding protobuf message types:
<Feature>
<Identifier>TemperatureController</Identifier>
<Command>
<Identifier>SetTemperature</Identifier>
<Parameter>
<Identifier>Temperature</Identifier>
<DataType>
<Basic>Real</Basic>
</DataType>
</Parameter>
</Command>
</Feature>
At runtime, this generates a protobuf-compatible type equivalent to:
[ProtoContract]
public class TemperatureController_SetTemperature_DynamicProtobufRequest
{
[ProtoMember(1)]
public Real Temperature { get; set; }
}
The package uses .NET Reflection.Emit to generate types at runtime using IL (Intermediate Language) instructions. This is more efficient than using dynamic or ExpandoObject because it creates actual .NET types that can be serialized by protobuf-net.
Types are cached in a shared ModuleBuilder to avoid duplicate generation and improve performance.
The package supports all SiLA2 communication patterns defined in the standard:
| Pattern | gRPC Pattern | Description | Use Case |
|---|---|---|---|
| Unobservable Property | Unary | Get current value immediately | Device status, configuration values |
| Observable Property | Server Streaming | Subscribe to continuous updates | Temperature monitoring, sensor readings |
| Unobservable Command | Unary | Execute and return result immediately | Set parameter, calibrate sensor |
| Observable Command | Multiple RPCs | Long-running operation with progress tracking | Start pump, run experiment |
Observable commands are the most complex pattern, involving multiple gRPC calls:
ExecuteObservableCommand() → Returns CommandConfirmation with CommandExecutionUUID{Command}_Info stream → Receives ExecutionInfo updates{Command}_Intermediate streamGetObservableCommandResult() after command completesThe package handles all SiLA2 data types:
Google.Protobuf.Collections.RepeatedField<T>┌─────────────────────────────────────────────────────────────┐
│ Client Application │
└───────────────────────────┬─────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ IDynamicMessageService │
│ - GetUnobservableProperty() │
│ - SubcribeObservableProperty() │
│ - ExecuteUnobservableCommand() │
│ - ExecuteObservableCommand() │
│ - GetObservableCommandResult() │
└───────────────────────────┬─────────────────────────────────┘
│
┌───────────────┴───────────────┐
▼ ▼
┌─────────────────────┐ ┌─────────────────────┐
│ IPayloadFactory │ │ protobuf-net │
│ │ │ GrpcClient │
│ - Generates request │ │ │
│ and response │ │ - Reflection-based │
│ types from FDL │ │ method invocation │
└──────────┬──────────┘ └─────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ DynamicProtobufTypeBuilder │
│ - IL Emission-based type generation │
│ - Creates ProtoContract-decorated classes │
│ - Manages type caching in shared ModuleBuilder │
└─────────────────────────────────────────────────────────────┘
Purpose: Generates .NET types at runtime using IL emission that are compatible with protobuf-net serialization.
Key Features:
[ProtoContract] attribute[ProtoMember(n)] attributesModuleBuilder to avoid duplicatesThread Safety: Type building uses a shared ModuleBuilder. The builder checks for existing types before creating new ones, but callers should implement locking if concurrent type generation for the same type name is possible.
Purpose: Analyzes SiLA2 FDL metadata to determine the correct .NET types for command parameters and property values.
Key Features:
FCPAffectedByMetadata_* pattern)Type Naming Convention:
{FeatureIdentifier}_{CommandIdentifier}_DynamicProtobufRequest/Response{FeatureIdentifier}_{PropertyIdentifier}_DynamicProtobufRequest/Response{CommandIdentifier}_IntermediateResponsesPurpose: Provides the main API for invoking SiLA2 operations using dynamically-generated types.
Key Features:
GrpcClient for code-first gRPCPerformance Consideration: Uses reflection to invoke generic methods, which has overhead compared to compile-time generated stubs. For high-throughput scenarios, consider the standard approach.
Purpose: Bridges between gRPC and protobuf-net serialization for dynamic types.
Key Features:
Marshaller<T> instances for gRPC transmissionByteSerializer for protobuf serializationByteSerializer<T>All examples assume you have:
using SiLA2.Communication.Services;
using SiLA2.Server.Utils;
using Grpc.Net.Client;
// Load feature definition
var feature = FeatureGenerator.ReadFeatureFromFile("TemperatureController-v1_0.sila.xml");
// Create gRPC channel
var channel = GrpcChannel.ForAddress("https://localhost:5001");
// Initialize dynamic message service
var dynamicMessageService = new DynamicMessageService(
new PayloadFactory(new DynamicAssemblyBuilder()));
// Read device status (returns immediately)
var response = dynamicMessageService.GetUnobservableProperty(
propertyName: "DeviceStatus",
channel: channel,
feature: feature);
// Extract the value using reflection
var statusProperty = response.GetType().GetProperty("DeviceStatus").GetValue(response, null);
var statusValue = statusProperty.GetType().GetProperty("Value").GetValue(statusProperty, null);
Console.WriteLine($"Device Status: {statusValue}");
Note: The response is a dynamically-typed object. You need to use reflection to extract property values, or cast to the appropriate SiLA2 basic type if known.
// Subscribe to continuous temperature updates
var temperatureStream = dynamicMessageService.SubcribeObservableProperty(
propertyName: "CurrentTemperature",
channel: channel,
feature: feature);
// Process streaming updates
await foreach (var update in temperatureStream)
{
var tempProperty = update.GetType().GetProperty("CurrentTemperature").GetValue(update, null);
var tempValue = ((Sila2.Org.Silastandard.Protobuf.Real)tempProperty).Value;
Console.WriteLine($"Temperature: {tempValue}°C");
// Cancel subscription after some condition
if (tempValue > 100.0)
break;
}
Cancellation: Use a CancellationToken in the foreach loop or break to stop receiving updates.
using Sila2.Org.Silastandard.Protobuf;
// Prepare command parameters
var parameters = new Dictionary<string, object>
{
{ "Temperature", new Real { Value = 25.5 } },
{ "Unit", new String { Value = "Celsius" } }
};
// Execute command (returns immediately)
var response = dynamicMessageService.ExecuteUnobservableCommand(
operationName: "SetTemperature",
channel: channel,
feature: feature,
payloadMap: parameters);
// Check response (if command has return values)
if (response != null)
{
var successProperty = response.GetType().GetProperty("Success");
if (successProperty != null)
{
var success = ((Boolean)successProperty.GetValue(response, null)).Value;
Console.WriteLine($"Command executed: {success}");
}
}
Parameters: Use the SiLA2 protobuf types from Sila2.Org.Silastandard.Protobuf namespace. Parameter names must match identifiers in the FDL exactly.
using Sila2.Org.Silastandard;
using Sila2.Org.Silastandard.Protobuf;
// Prepare command parameters
var parameters = new Dictionary<string, object>
{
{ "TargetTemperature", new Real { Value = 80.0 } },
{ "Duration", new Real { Value = 300.0 } } // 5 minutes
};
// Initiate observable command
var result = dynamicMessageService.ExecuteObservableCommand(
operationName: "StartHeating",
channel: channel,
feature: feature,
payloadMap: parameters);
var commandConfirmation = result.Item1;
var executionInfoStream = result.Item2;
var intermediateStream = result.Item3; // null if no intermediate responses
var responseType = result.Item4;
Console.WriteLine($"Command initiated: {commandConfirmation.CommandExecutionUUID.Value}");
// Monitor execution progress
await foreach (var executionInfo in executionInfoStream)
{
Console.WriteLine($"Status: {executionInfo.CommandStatus}");
Console.WriteLine($"Progress: {executionInfo.ProgressInfo?.Value * 100:F1}%");
if (executionInfo.CommandStatus == ExecutionInfo.Types.CommandStatus.FinishedSuccessfully)
{
Console.WriteLine("Command completed successfully!");
break;
}
else if (executionInfo.CommandStatus == ExecutionInfo.Types.CommandStatus.FinishedWithError)
{
Console.WriteLine($"Command failed: {executionInfo.Message?.Value}");
break;
}
}
// Retrieve final result
var finalResult = dynamicMessageService.GetObservableCommandResult(
cmdId: commandConfirmation.CommandExecutionUUID,
operationName: "StartHeating",
channel: channel,
feature: feature,
responseType: responseType);
// Extract result values
var finalTemp = finalResult.GetType().GetProperty("FinalTemperature");
if (finalTemp != null)
{
var temp = ((Real)finalTemp.GetValue(finalResult, null)).Value;
Console.WriteLine($"Final temperature: {temp}°C");
}
// For commands that define IntermediateResponse in FDL
var result = dynamicMessageService.ExecuteObservableCommand(
operationName: "RunExperiment",
channel: channel,
feature: feature,
payloadMap: parameters);
var executionInfoStream = result.Item2;
var intermediateStream = result.Item3;
// Process intermediate responses in parallel with execution info
var intermediateTask = Task.Run(async () =>
{
if (intermediateStream != null)
{
await foreach (var intermediate in intermediateStream)
{
// Extract intermediate data (structure depends on FDL definition)
var currentReading = intermediate.GetType()
.GetProperty("CurrentReading")?.GetValue(intermediate, null);
if (currentReading != null)
{
var reading = ((Real)currentReading).Value;
Console.WriteLine($"Intermediate reading: {reading}");
}
}
}
});
// Monitor execution status
await foreach (var executionInfo in executionInfoStream)
{
if (executionInfo.CommandStatus == ExecutionInfo.Types.CommandStatus.FinishedSuccessfully ||
executionInfo.CommandStatus == ExecutionInfo.Types.CommandStatus.FinishedWithError)
{
break;
}
}
// Wait for intermediate task to complete
await intermediateTask;
// Get final result
var finalResult = dynamicMessageService.GetObservableCommandResult(
result.Item1.CommandExecutionUUID,
"RunExperiment",
channel,
feature,
result.Item4);
Structures in SiLA2 are nested message types:
// FDL defines a structure like:
// <StructureType>
// <Element>
// <Identifier>X</Identifier>
// <DataType><Basic>Real</Basic></DataType>
// </Element>
// <Element>
// <Identifier>Y</Identifier>
// <DataType><Basic>Real</Basic></DataType>
// </Element>
// </StructureType>
// Create structure instance dynamically
var structureType = Type.GetType("DynamicallyGenerated_CoordinateStructure");
var structureInstance = Activator.CreateInstance(structureType);
// Set nested properties
var xProperty = structureInstance.GetType().GetProperty("X");
xProperty.SetValue(structureInstance, new Real { Value = 10.5 });
var yProperty = structureInstance.GetType().GetProperty("Y");
yProperty.SetValue(structureInstance, new Real { Value = 20.3 });
// Use in command parameters
var parameters = new Dictionary<string, object>
{
{ "Position", structureInstance }
};
Lists use Google.Protobuf.Collections.RepeatedField<T>:
using Google.Protobuf.Collections;
using Sila2.Org.Silastandard.Protobuf;
// Create a list of strings
var stringList = new RepeatedField<String>();
stringList.Add(new String { Value = "First" });
stringList.Add(new String { Value = "Second" });
stringList.Add(new String { Value = "Third" });
var parameters = new Dictionary<string, object>
{
{ "Names", stringList }
};
var response = dynamicMessageService.ExecuteUnobservableCommand(
"ProcessNames", channel, feature, parameters);
Constrained types (e.g., Real with min/max) are handled transparently:
// FDL defines constraint: <MinimalInclusive>0</MinimalInclusive>
// The PayloadFactory resolves this to the underlying Real type
var parameters = new Dictionary<string, object>
{
{ "Speed", new Real { Value = 50.0 } } // Constraint validation happens server-side
};
SiLA2 features can define metadata that affects which commands/properties are available. The package supports the FCPAffectedByMetadata_{MetadataIdentifier} pattern:
// Get list of calls affected by specific metadata
var response = dynamicMessageService.GetUnobservableProperty(
propertyName: "FCPAffectedByMetadata_StringMetadata",
channel: channel,
feature: feature);
// Extract affected calls list
var affectedCallsProperty = response.GetType().GetProperty("AffectedCalls");
var affectedCalls = (Google.Protobuf.Collections.RepeatedField<String>)affectedCallsProperty.GetValue(response);
foreach (var call in affectedCalls)
{
Console.WriteLine($"Affected call: {call.Value}");
}
For features with custom defined data types in FDL:
<DataTypeDefinition>
<Identifier>Temperature</Identifier>
<DataType>
<Constrained>
<DataType><Basic>Real</Basic></DataType>
<Constraints>
<MinimalInclusive>-273.15</MinimalInclusive>
<MaximalInclusive>1000.0</MaximalInclusive>
</Constraints>
</Constrained>
</DataType>
</DataTypeDefinition>
The PayloadFactory automatically resolves custom types by traversing the FDL definition tree:
// Usage is transparent - just use the parameter name
var parameters = new Dictionary<string, object>
{
{ "SetPoint", new Real { Value = 25.0 } } // Temperature type resolved to Real
};
ModuleBuilder Caching: The DynamicProtobufTypeBuilder uses a shared ModuleBuilder for type generation. While type definition operations are thread-safe, checking for existing types is not atomic.
Recommendation: For multi-threaded scenarios where the same feature might be loaded concurrently, implement a locking strategy around feature initialization:
private static readonly SemaphoreSlim _featureLoadLock = new SemaphoreSlim(1, 1);
private static readonly Dictionary<string, Feature> _featureCache = new();
public async Task<Feature> LoadFeatureAsync(string featurePath)
{
await _featureLoadLock.WaitAsync();
try
{
if (!_featureCache.ContainsKey(featurePath))
{
var feature = FeatureGenerator.ReadFeatureFromFile(featurePath);
_featureCache[featurePath] = feature;
}
return _featureCache[featurePath];
}
finally
{
_featureLoadLock.Release();
}
}
using Grpc.Core;
try
{
var response = dynamicMessageService.ExecuteUnobservableCommand(
"SetTemperature", channel, feature, parameters);
}
catch (RpcException ex) when (ex.StatusCode == StatusCode.InvalidArgument)
{
// SiLA2 validation error (e.g., parameter constraint violation)
Console.WriteLine($"Validation error: {ex.Status.Detail}");
}
catch (RpcException ex) when (ex.StatusCode == StatusCode.FailedPrecondition)
{
// SiLA2 defined execution error
Console.WriteLine($"Execution error: {ex.Status.Detail}");
// Parse SiLA2 error details from metadata
var errorType = ex.Trailers.GetValue("sila2-error-type");
var errorIdentifier = ex.Trailers.GetValue("sila2-error-identifier");
}
catch (RpcException ex)
{
// Other gRPC errors (network, authentication, etc.)
Console.WriteLine($"gRPC error: {ex.StatusCode} - {ex.Status.Detail}");
}
catch (ArgumentException ex)
{
// Invalid property/command name or parameter
Console.WriteLine($"Invalid parameter: {ex.Message}");
}
| Aspect | SiLA2.Communication (Dynamic) | Standard XSLT/protoc |
|---|---|---|
| Setup Time | Instant (load FDL at runtime) | Requires build step |
| Flexibility | Load any feature dynamically | Must recompile for new features |
| Performance | Slower (reflection overhead) | Faster (compiled code) |
| Type Safety | Runtime checks only | Compile-time type checking |
| Code Completion | Limited (dynamic types) | Full IntelliSense support |
| Binary Size | Smaller (no generated code) | Larger (generated assemblies) |
| Use Case | Universal clients, testing | Production feature implementations |
| Debugging | More complex (reflection) | Standard debugging |
| Maintenance | No code generation to maintain | MSBuild targets required |
Performance Benchmark (approximate):
For most SiLA2 operations (which involve I/O, device communication, etc.), this overhead is negligible compared to the operation duration.
Main interface for dynamic SiLA2 communication.
public interface IDynamicMessageService
{
// Unobservable property access
object GetUnobservableProperty(
string propertyName,
GrpcChannel channel,
Feature feature,
Grpc.Core.Metadata metadata = null);
// Observable property subscription
IAsyncEnumerable<object> SubcribeObservableProperty(
string propertyName,
GrpcChannel channel,
Feature feature,
Grpc.Core.Metadata metadata = null);
// Unobservable command execution
object ExecuteUnobservableCommand(
string operationName,
GrpcChannel channel,
Feature feature,
IDictionary<string, object> payloadMap = null,
Grpc.Core.Metadata metadata = null);
// Observable command initiation
Tuple<CommandConfirmation, IAsyncEnumerable<ExecutionInfo>,
IAsyncEnumerable<object>, Type> ExecuteObservableCommand(
string operationName,
GrpcChannel channel,
Feature feature,
IDictionary<string, object> payloadMap = null,
Grpc.Core.Metadata metadata = null);
// Observable command result retrieval
object GetObservableCommandResult(
CommandExecutionUUID cmdId,
string operationName,
GrpcChannel channel,
Feature feature,
Type responseType,
Grpc.Core.Metadata metadata = null);
}
Interface for generating dynamic protobuf types from FDL metadata.
public interface IPayloadFactory
{
// Command payload types (request and response)
Tuple<Type, Type> GetCommandPayloadTypes(
Feature feature,
string operation);
// Observable command with intermediate responses
Tuple<Type, Type, Type> GetCommandPayloadTypesWithIntermediateCommandResponseType(
Feature feature,
string operation);
// Property payload types
Tuple<Type, Type> GetPropertyPayloadTypes(
Feature feature,
string property);
}
Provides shared ModuleBuilder for type caching.
public interface IDynamicAssemblyBuilder
{
ModuleBuilder ModuleBuilder { get; }
}
This package is part of the sila_csharp project.
git clone --recurse-submodules https://gitlab.com/SiLA2/sila_csharp.git
cd sila_csharp/src
dotnet build SiLA2.Communication/SiLA2.Communication.csproj
dotnet test Tests/SiLA2.Communication.Tests/SiLA2.Communication.Tests.csproj
dotnet test Tests/SiLA2.IntegrationTests.Server.Tests/SiLA2.IntegrationTests.Server.Tests.csproj --filter "FullyQualifiedName~DynamicClient"
SiLA2.Communication/
├── Protobuf/
│ ├── DynamicProtobufTypeBuilder.cs # IL emission-based type generation
│ ├── ProtobufMarshaller.cs # gRPC marshalling for dynamic types
│ └── ByteSerializer.cs # protobuf-net serialization
├── Services/
│ ├── DynamicMessageService.cs # Main gRPC client implementation
│ ├── PayloadFactory.cs # FDL-to-Type mapper
│ ├── DynamicAssemblyBuilder.cs # Shared ModuleBuilder provider
│ └── Interfaces/
└── SiLA2FrameworkEntities.cs # SiLA2 base protobuf types
This project is licensed under the MIT License.
Christoph Pohl (@Chamundi)
For security vulnerabilities, please refer to the SiLA2 Vulnerability Policy.
Questions or Issues?
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 net5.0 was computed. net5.0-windows net5.0-windows was computed. net6.0 net6.0 was computed. net6.0-android net6.0-android was computed. net6.0-ios net6.0-ios was computed. net6.0-maccatalyst net6.0-maccatalyst was computed. net6.0-macos net6.0-macos was computed. net6.0-tvos net6.0-tvos was computed. net6.0-windows net6.0-windows was computed. net7.0 net7.0 was computed. net7.0-android net7.0-android was computed. net7.0-ios net7.0-ios was computed. net7.0-maccatalyst net7.0-maccatalyst was computed. net7.0-macos net7.0-macos was computed. net7.0-tvos net7.0-tvos was computed. net7.0-windows net7.0-windows was computed. net8.0 net8.0 was computed. net8.0-android net8.0-android was computed. net8.0-browser net8.0-browser was computed. net8.0-ios net8.0-ios was computed. net8.0-maccatalyst net8.0-maccatalyst was computed. net8.0-macos net8.0-macos was computed. net8.0-tvos net8.0-tvos was computed. net8.0-windows net8.0-windows was computed. net9.0 net9.0 was computed. net9.0-android net9.0-android was computed. net9.0-browser net9.0-browser was computed. net9.0-ios net9.0-ios was computed. net9.0-maccatalyst net9.0-maccatalyst was computed. net9.0-macos net9.0-macos was computed. net9.0-tvos net9.0-tvos was computed. net9.0-windows net9.0-windows was computed. net10.0 net10.0 is compatible. net10.0-android net10.0-android was computed. net10.0-browser net10.0-browser was computed. net10.0-ios net10.0-ios was computed. net10.0-maccatalyst net10.0-maccatalyst was computed. net10.0-macos net10.0-macos was computed. net10.0-tvos net10.0-tvos was computed. net10.0-windows net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 netcoreapp2.0 was computed. netcoreapp2.1 netcoreapp2.1 was computed. netcoreapp2.2 netcoreapp2.2 was computed. netcoreapp3.0 netcoreapp3.0 was computed. netcoreapp3.1 netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 netstandard2.0 is compatible. netstandard2.1 netstandard2.1 was computed. |
| .NET Framework | net461 net461 was computed. net462 net462 was computed. net463 net463 was computed. net47 net47 was computed. net471 net471 was computed. net472 net472 was computed. net48 net48 was computed. net481 net481 was computed. |
| MonoAndroid | monoandroid monoandroid was computed. |
| MonoMac | monomac monomac was computed. |
| MonoTouch | monotouch monotouch was computed. |
| Tizen | tizen40 tizen40 was computed. tizen60 tizen60 was computed. |
| Xamarin.iOS | xamarinios xamarinios was computed. |
| Xamarin.Mac | xamarinmac xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos xamarinwatchos was computed. |
Showing the top 2 NuGet packages that depend on SiLA2.Communication:
| Package | Downloads |
|---|---|
|
SiLA2.Frontend.Razor
Web Frontend Extension for SiLA2.Server Package |
|
|
SiLA2.Client.Dynamic
SiLA2.Client.Dynamic Package |
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 10.2.4 | 1,928 | 3/13/2026 |
| 10.2.3 | 1,534 | 3/7/2026 |
| 10.2.2 | 1,850 | 2/12/2026 |
| 10.2.1 | 1,917 | 1/25/2026 |
| 10.2.0 | 2,245 | 12/23/2025 |
| 10.1.0 | 2,459 | 11/29/2025 |
| 10.0.0 | 2,888 | 11/11/2025 |
| 9.0.4 | 3,150 | 6/25/2025 |
| 9.0.3 | 3,096 | 6/21/2025 |
| 9.0.2 | 3,150 | 1/6/2025 |
| 9.0.1 | 3,143 | 11/17/2024 |
| 9.0.0 | 3,140 | 11/13/2024 |
| 8.1.2 | 3,190 | 10/20/2024 |
| 8.1.1 | 3,254 | 8/31/2024 |
| 8.1.0 | 3,825 | 2/11/2024 |
| 8.0.0 | 3,561 | 11/15/2023 |
| 7.5.4 | 3,210 | 10/27/2023 |
| 7.5.3 | 3,369 | 7/19/2023 |
| 7.5.2 | 3,305 | 7/4/2023 |