![]() |
VOOZH | about |
dotnet add package Siemens.AspNet.MinimalApi.Sdk.Contracts --version 7.5.6
NuGet\Install-Package Siemens.AspNet.MinimalApi.Sdk.Contracts -Version 7.5.6
<PackageReference Include="Siemens.AspNet.MinimalApi.Sdk.Contracts" Version="7.5.6" />
<PackageVersion Include="Siemens.AspNet.MinimalApi.Sdk.Contracts" Version="7.5.6" />Directory.Packages.props
<PackageReference Include="Siemens.AspNet.MinimalApi.Sdk.Contracts" />Project file
paket add Siemens.AspNet.MinimalApi.Sdk.Contracts --version 7.5.6
#r "nuget: Siemens.AspNet.MinimalApi.Sdk.Contracts, 7.5.6"
#:package Siemens.AspNet.MinimalApi.Sdk.Contracts@7.5.6
#addin nuget:?package=Siemens.AspNet.MinimalApi.Sdk.Contracts&version=7.5.6Install as a Cake Addin
#tool nuget:?package=Siemens.AspNet.MinimalApi.Sdk.Contracts&version=7.5.6Install as a Cake Tool
The Siemens.AspNet.MinimalApi.Sdk.Contracts NuGet package defines essential interfaces, attributes, and base classes
designed to standardize common functionalities required for building Minimal APIs. These abstractions support dependency
injection, JSON serialization, difference tracking, and advanced validation scenarios.
This package provides foundational contracts that facilitate a structured, extensible, and maintainable Minimal API architecture.
📐 Activators
IActivatorIAsyncActivator<T>ICustomActivator<T>📦 JSON Serialization & Differencing
IJsonSerializer for robust serialization and deserialization.IJsonDiffer for detailed JSON comparison and difference detection.✔️ Advanced Validation
IAttributeValidator for recursive and attribute-driven validation.
CustomValidatorBase<T, TAttribute> for custom synchronous validation logic.
AsyncCustomValidatorBase<T, TAttribute> for asynchronous custom validation.
Request validation abstractions:
RequestValidator<TRequest> and AsyncRequestValidator<TRequest> for complete object validation.PatchRequestValidator<TRequest> and AsyncPatchRequestValidator<TRequest> specifically tailored for PATCH
scenarios.dotnet add package Siemens.AspNet.MinimalApi.Sdk.Contracts
public class ExampleService
{
private readonly IActivator _activator;
public ExampleService(IActivator activator)
{
_activator = activator;
}
public async Task<MyClass> CreateMyClassAsync()
{
return await _activator.CreateInstanceAsync<MyClass>();
}
}
public void CheckJsonDifferences(IJsonDiffer jsonDiffer)
{
var differences = jsonDiffer.FindDifferences("{\"name\":\"John\"}", "{\"name\":\"Jane\"}");
foreach (var diff in differences)
{
Console.WriteLine($"Property: {diff.MemberPath}, Difference: {diff.MismatchType}");
}
}
internal static class AddAlphaNumericValidatorExtension
{
internal static void AddAlphaNumericValidator(this IServiceCollection services)
{
services.AddSingletonIfNotExists<ICustomValidator, AlphaNumericValidator>();
}
}
public class AlphaNumericAttribute(params string[] sampleValues) : CustomValidationAttribute<AlphaNumericValidator>(string.Empty, sampleValues);
public sealed class AlphaNumericValidator : CustomValidatorBase<string, AlphaNumericAttribute>
{
protected override IEnumerable<ValidationErrorDetailsBase> Validate(PropertyInfo propertyInfo,
AlphaNumericAttribute attribute,
string? source)
{
if (source == null)
{
yield break;
}
if (source.Any(ch => !char.IsLetterOrDigit(ch)))
{
var sampleValues = attribute.SampleValues.Any() ? attribute.SampleValues : ["sample123"];
yield return new ValidationErrorDetailsBase
{
Errors = [$"{propertyInfo.Name} must be alphanumeric."],
Samples = sampleValues
};
}
}
}
We provide another level of validation if you have an data historie to compare current value against your privious value. (Historical Validation)
internal static class AddIsNotChangeableAfterDeploymentValidatorExtension
{
internal static void AddIsNotChangeableAfterDeploymentValidator(this IServiceCollection services)
{
services.AddSingletonIfNotExists<IComplexCustomValidator, IsNotChangableAfterDeploymentValidator>();
}
}
internal sealed class IsNotChangeableAfterDeploymentAttribute() : ComplexCustomValidationAttribute<IsNotChangableAfterDeploymentValidator>(string.Empty, [])
{
}
internal sealed class IsNotChangableAfterDeploymentValidator() : ComplexCustomValidator<AwsS3Bucket, string?, IsNotChangeableAfterDeploymentAttribute>
{
protected override IEnumerable<ValidationErrorDetailsBase> Validate(PropertyInfo propertyInfo,
IsNotChangeableAfterDeploymentAttribute attribute,
AwsS3Bucket capability,
string? currentValue,
string? lastValue)
{
if (capability.IsDeployed.IsFalse())
{
yield break;
}
if (currentValue != lastValue)
{
yield return new ValidationErrorDetailsBase
{
Errors = [$"You are not allowed to change the: {propertyInfo.Name} after the capability was deployed ! This would cause in critical male function of your project"],
Samples = [currentValue]
};
}
}
}
This request validator shows a sample without attribute validation.
public static class AddCreateFormsConfigurationRequestValidatorExtension
{
internal static void AddCreateFormsConfigurationRequestValidator(this IServiceCollection services,
IConfiguration configuration)
{
services.AddFormsConfigurationSettings(configuration);
services.AddSingletonIfNotExists<CreateFormsConfigurationRequestValidator>();
}
}
internal sealed class CreateFormsConfigurationRequestValidator : RequestValidator<CreateFormsConfigurationRequest>
{
protected override IEnumerable<PropertyValidationResult> GetValidationErrors(CreateFormsConfigurationRequest request)
{
// Your validation code here
if (request.FormsId.IsNull())
{
var errorDetails = new ValidationErrorDetails
{
CurrentValue = request.FormsId,
Errors = [$"{nameof(request.FormsId)} must not be null. Only GUID or a long is valid for the {nameof(request.FormsId)}"],
Samples = ["a1b2c3d4-e5f6-7890-1234-567890abcdef", "1"]
};
yield return new PropertyValidationResult(nameof(request.FormsId), errorDetails);
}
}
}
In this sample the async validator is used to validate a CreateDeploymentRequest object. The validator checks for the
presence of required properties and validates them using the IAttributeValidator interface.
public sealed record CreateDeploymentRequest
{
[ValidEnum]
public required Stage Stage { get; init; }
};
internal static class AddCreateDeploymentRequestValidatorExtension
{
internal static void AddCreateDeploymentRequestValidator(this IServiceCollection services)
{
services.AddSingletonIfNotExists<CreateDeploymentRequestValidator>();
}
}
internal sealed class CreateDeploymentRequestValidator(IAttributeValidator attributeValidator) : AsyncRequestValidator<CreateDeploymentRequest>
{
protected override async IAsyncEnumerable<PropertyValidationResult> GetValidationErrorsAsync(CreateDeploymentRequest request,
[EnumeratorCancellation] CancellationToken cancellationToken = default)
{
var errors = await attributeValidator.ValidateAsync(request, cancellationToken).ConfigureAwait(false);
foreach (var propertyValidationResult in errors)
{
yield return propertyValidationResult;
}
}
}
The Injectable Endpoint feature introduces a clean, modular way to register Minimal API endpoints directly through dependency injection. Instead of mapping endpoints manually inside Program.cs, you can now inject them into your application as services.
This makes your API endpoints:
application.Map calls necessary in Program.cs or somewhere else → resolved automaticallyInterface:
public interface IEndpoint
{
void Map(IEndpointRouteBuilder versionBasePath);
}
Sample:
internal static class AddCreateCapabilityEndpointExtension
{
internal static void AddCreateCapabilityEndpoint(this IServiceCollection services)
{
services.AddSingletonIfNotExists<IEndpoint, CreateCapabilityEndpoint>();
}
}
internal class CreateCapabilityEndpoint(CapabilityProvider capabilityProvider) : IEndpoint
{
public void Map(IEndpointRouteBuilder endpoints)
{
// Your endpoint registration logic here :)
endpoints.MapPost("/capabilities", async (CreateCapabilityRequest request, CancellationToken cancellationToken) =>
{
var capability = await capabilityProvider.CreateAsync(request, cancellationToken);
return Results.Created($"/capabilities/{capability.Id}", capability);
})
}
}
Registration:
As you can see no Map necessary. We just register the endpoint
namespace Sdc.Console.Api.Capabilities.V1
{
internal static class CreateStartup
{
internal static void AddCreate(this IServiceCollection services,
IConfiguration configuration)
{
services.AddCreateCapabilityCommand(configuration);
services.AddCreateCapabilityEndpoint();
}
}
}
The Siemens.AspNet.MinimalApi.Sdk already provides out of the box some helpers for the most common types. You can use
them directly or implement your own converters.
| Converter Name | Description |
|---|---|
DateTimeOffsetConverter |
Converts DateTimeOffset values to and from string format (typically ISO 8601) for DynamoDB. |
DictionaryStringObjectConverter |
Handles conversion of Dictionary<string, object> to a DynamoDB-compatible format. |
DictionaryStringObjectNullableConverter |
Similar to DictionaryStringObjectConverter but allows nullable dictionary handling. |
ImmutableDictionaryStringObjectNullableConverter |
Converts ImmutableDictionary<string, object?> to a format compatible with DynamoDB, supporting null values. |
TimeSpanConverter |
Serializes TimeSpan values as string and deserializes them back. Useful for time duration storage in DynamoDB. |
Sample:
[DynamoDBTable("Capability")]
public record CapabilityEntity
{
[DynamoDBHashKey]
public required Guid Id { get; init; }
[DynamoDBRangeKey]
public required string DeploymentId { get; init; } = CapabilityConstants.DefaultDeploymentId;
[DynamoDBProperty(typeof(DateTimeOffsetConverter))]
public required DateTimeOffset LastUpdatedDate { get; init; } = DateTimeOffset.UtcNow;
}
The IDynamoEntityMapper brings already most common converter with it (Siemens.AspNet.MinimalApi.Sdk). You can just use
it.
In exception cases, you can implement your own converter by implementing IDynamoTypeConverter or
IAsyncDynamoTypeConverter.
| Converter Name | Description |
|---|---|
EnumToStringConverter |
Converts enum values to their string representation and vice versa. Useful for storing enums as strings in DynamoDB. |
EnumerableToImmutableConverter |
Converts IEnumerable<T> to ImmutableList<T> for safe, immutable handling of collections during mapping. |
ImmutableToListConverter |
Converts ImmutableList<T> to List<T> to support serialization or mutable collection use cases. |
TimeSpanToStringConverter |
Serializes TimeSpan values as ISO 8601-like strings and parses them back. Enables human-readable time span storage. |
public sealed class MyHandler(IDynamoEntityMapper mapper)
{
public async Task<MyDto> HandleAsync(object rawData, CancellationToken cancellationToken)
{
return await mapper.ConvertAsync<MyDto>(rawData, cancellationToken);
}
}
Custom property converter example:
internal static class AddTimeSpanToStringConverterExtension
{
internal static void AddTimeSpanToStringConverter(this IServiceCollection services)
{
services.AddSingletonIfNotExists<IDynamoTypeConverter, TimeSpanToStringConverter>();
}
}
internal sealed class TimeSpanToStringConverter : IDynamoTypeConverter
{
public bool CanConvert(Type source,
Type target)
{
var canConvert = source == typeof(TimeSpan) &&
target == typeof(string);
return canConvert;
}
public object? ConvertObject(object? source,
Type targetType)
{
return source?.ToString();
}
}
IActivator for instance creation with dependency injection.IAsyncActivator for instance creation with dependency injection in asynchronous contexts.IJsonDiffer for tracking JSON changes in PATCH requests.IAttributeValidator custom for attribute-driven validation scenarios.IAttributeValidator interface.Additional details and examples are available in the repository documentation and upcoming online resources.
Your contributions and feedback are welcomed! Please create issues or pull requests to enhance this package.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | 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. |
Showing the top 1 NuGet packages that depend on Siemens.AspNet.MinimalApi.Sdk.Contracts:
| Package | Downloads |
|---|---|
|
Siemens.AspNet.MinimalApi.Sdk
A library which contains following functions: - Siemens.AspNet.MinimalApi.Sdk |
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 7.5.6 | 83 | 6/17/2026 |
| 7.5.5 | 23 | 6/17/2026 |
| 7.5.4 | 26 | 6/17/2026 |
| 7.5.3 | 140 | 6/17/2026 |
| 7.5.2 | 49 | 6/16/2026 |
| 7.5.1 | 2,805 | 6/2/2026 |
| 7.5.0 | 145 | 5/12/2026 |
| 7.5.0-alpha.16 | 62 | 5/18/2026 |
| 7.5.0-alpha.15 | 55 | 5/18/2026 |
| 7.5.0-alpha.12 | 66 | 5/12/2026 |
| 7.5.0-alpha.11 | 61 | 5/12/2026 |
| 7.5.0-alpha.10 | 60 | 5/12/2026 |
| 7.5.0-alpha.3 | 67 | 5/11/2026 |
| 7.4.6 | 38 | 6/2/2026 |
| 7.4.5 | 565 | 5/24/2026 |
| 7.4.4 | 39 | 5/18/2026 |
| 7.4.3 | 44 | 5/18/2026 |
| 7.4.2 | 2,497 | 5/11/2026 |
| 7.4.1 | 45 | 5/11/2026 |
| 7.4.0 | 6,107 | 5/6/2026 |