Siemens.AspNet.MinimalApi.Sdk
7.5.1
Prefix Reserved
dotnet add package Siemens.AspNet.MinimalApi.Sdk --version 7.5.1
NuGet\Install-Package Siemens.AspNet.MinimalApi.Sdk -Version 7.5.1
<PackageReference Include="Siemens.AspNet.MinimalApi.Sdk" Version="7.5.1" />
<PackageVersion Include="Siemens.AspNet.MinimalApi.Sdk" Version="7.5.1" />
<PackageReference Include="Siemens.AspNet.MinimalApi.Sdk" />
paket add Siemens.AspNet.MinimalApi.Sdk --version 7.5.1
#r "nuget: Siemens.AspNet.MinimalApi.Sdk, 7.5.1"
#:package Siemens.AspNet.MinimalApi.Sdk@7.5.1
#addin nuget:?package=Siemens.AspNet.MinimalApi.Sdk&version=7.5.1
#tool nuget:?package=Siemens.AspNet.MinimalApi.Sdk&version=7.5.1
Siemens.AspNet.Minimal.Sdk
The Siemens.AspNet.Minimal.Sdk NuGet package offers a streamlined approach to building Minimal APIs in ASP.NET
Core. It includes pre-configured defaults, opinionated helpers, and seamless integrations that accelerate development
and simplify application setup.
📖 Overview
This SDK is designed to remove boilerplate code and help you focus on what matters: your business logic.
✅ Key Features
- ⚙️ Pre-configured application startup
- ☁️ AWS integration (optional)
- 🗄️ Database connectivity (supports AWS DynamoDB)
- 🔄 Consistent JSON serialization settings
- 🔐 Security best practices (JWT, OAuth2, security headers)
- ✔️ Custom validation support
- 📘 Auto-configured OpenAPI/Swagger
📦 Installation
Using the .NET CLI
dotnet add package Siemens.AspNet.Minimal.Sdk
⚡ Quickstart Example
Below is a minimal setup using ServerlessMinimalWebApi, designed to get you started in seconds:
using Siemens.AspNet.MinimalApi.Sdk;
var webApi = new ServerlessMinimalWebApi();
webApi.BasePath = "api/fieldingtool";
webApi.Versions = [1, 2];
webApi.RegisterServices = (service,
config) =>
// Domain service registrations
// service.AddApi(config);
webApi.Run(args);
// This is important that you are able to use
// API test via WebApplicationFactory<Program>
// https://learn.microsoft.com/en-us/aspnet/core/test/integration-tests?view=aspnetcore-8.0
namespace Siemens.AspNet.ClientGenerator.Mcp.Server
{
#pragma warning disable CA1515 // Needed for testing
public class Program;
#pragma warning restore CA1515 // Needed for testing
}
🧠 Key Concepts
| Component | Description |
|---|---|
ServerlessMinimalWebApi |
Opinionated builder for hosting, logging, and config setup |
RegisterServices |
Delegate for adding services to the DI container |
Run |
Starts the web application |
partial Program |
Enables integration testing with WebApplicationFactory<Program> |
IEndpoint |
Use this interface to implement endpoints. Injectable Endpoint |
Helpers and utils
Activator Usage
public class ExampleService
{
private readonly IActivator _activator;
public ExampleService(IActivator activator)
{
_activator = activator;
}
public async Task<MyClass> CreateMyClassAsync()
{
return await _activator.CreateInstanceAsync<MyClass>();
}
}
JSON Differ Example
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}");
}
}
Custom Validation with Attributes
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
};
}
}
}
Complex-Custom Validation with Attributes
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]
};
}
}
}
Request Validator (sync)
This request validator shows a sample without attribute validation.
public static class AddCreateFormsConfigurationRequestValidatorExtension
{
internal static void AddCreateFormsConfigurationRequestValidator(this IServiceCollection services,
IConfiguration configuration)
{
services.AddLanguageValidator();
services.AddFormsConfigurationSettings(configuration);
services.AddSingletonIfNotExists<CreateFormsConfigurationRequestValidator>();
}
}
internal sealed class CreateFormsConfigurationRequestValidator(LanguageValidator languageValidator,
FormsConfigurationSettings formsConfigurationSettings,
IAttributeValidator attributeValidator) : RequestValidator<CreateFormsConfigurationRequest>(IAttributeValidator attributeValidator)
{
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);
}
}
}
Async Request Validator
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;
}
}
}
Injectable Endpoint
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:
- Discoverable – any registered IEndpoint implementation will be automatically picked up.
- Modular – endpoints are defined in self-contained classes.
- No
application.Mapcalls necessary in Program.cs or somewhere else → resolved automatically - Provides the option in future to configure which endpoints are available and which not.
Interface:
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();
}
}
}
AWS DynamoDB Custom Converters
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;
}
AWS Dynamo Entity Mapper (POC)
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();
}
}
🔖 Available Validation Attributes
The SDK provides a comprehensive set of validation attributes for common validation scenarios:
| Attribute | Description |
|---|---|
AlphaNumericAttribute |
Validates that the value contains only letters and digits |
ConsecutivePeriodsAttribute |
Validates against consecutive periods in a string |
ContainsAllOfAttribute |
Validates that the value contains all specified substrings |
ContainsAnyOfAttribute |
Validates that the value contains at least one of the specified substrings |
ContainsAttribute |
Validates that the value contains a specific substring |
ContainsNoNullAttribute |
Validates that a collection contains no null values |
ContainsNoneOfAttribute |
Validates that the value contains none of the specified substrings |
DateTimeIsUtcAttribute |
Validates that the DateTime value is in UTC timezone |
DateTimeOffsetIsUtcAttribute |
Validates that the DateTimeOffset value is in UTC timezone |
DoesNotContainAttribute |
Validates that the value does not contain a specific substring |
EmailAttribute |
Validates email address format and optional domain |
EndWithDigitOrLetterAttribute |
Validates that the value ends with a digit or letter |
EndWithLetterAttribute |
Validates that the value ends with a letter |
EndsWithAttribute |
Validates that the value ends with a specific suffix |
EnumIsDefinedAttribute |
Validates that the enum value is a defined member of its enum type |
EvenAttribute |
Validates that the numeric value is even |
FileExtensionsAttribute |
Validates file extensions against an allowed list |
ForbiddenCharactersAttribute |
Validates against forbidden characters |
GuidIsNotEmptyAttribute |
Validates that the GUID value is not empty |
IsInRangeAttribute |
Validates that the value is within a specified range |
IsNotContainingAttribute |
Validates that a string or collection does not contain a specified value |
IsNotEmptyAttribute |
Validates that the value is not empty |
IsNotNullAttribute |
Validates that the value is not null |
IsNotWhitespaceAttribute |
Validates that the value is not whitespace |
LengthAttribute |
Validates string length within a min/max range |
LettersOnlyAttribute |
Validates that the value contains only letters |
MaxLengthAttribute |
Validates the maximum length of a string |
MaxValueAttribute |
Validates the maximum numeric value |
MinLengthAttribute |
Validates the minimum length of a string |
MinLetterCountAttribute |
Validates the minimum number of letters |
MinValueAttribute |
Validates the minimum numeric value |
NegativeAttribute |
Validates that the numeric value is negative |
NoDuplicateValuesAttribute |
Validates that a collection contains no duplicate values |
NoLeadingWhitespacesAttribute |
Validates that the value has no leading whitespace |
NoTrailingWhitespacesAttribute |
Validates that the value has no trailing whitespace |
NoValidationAttribute |
Skips validation for the property |
NonZeroAttribute |
Validates that the numeric value is not zero |
NumbersOnlyAttribute |
Validates that the value contains only digits |
OddAttribute |
Validates that the numeric value is odd |
OnlyLowerLettersAttribute |
Validates that all letter characters are lowercase |
PeriodsAdjacentHyphensAttribute |
Validates against periods adjacent to hyphens |
PhoneAttribute |
Validates phone number format |
PositiveAttribute |
Validates that the numeric value is positive |
RegexAttribute |
Validates against a custom regular expression pattern |
RegularExpressionAttribute |
Validates against a regular expression |
SpecialCharactersNotAllowedAttribute |
Validates that only alphanumeric, underscore, and hyphen characters are used |
StartWithDigitOrLetterAttribute |
Validates that the value starts with a digit or letter |
StartWithLetterAttribute |
Validates that the value starts with a letter |
StartsWithAttribute |
Validates that the value starts with a specific prefix |
StringLengthAttribute |
Validates string length within a min/max range |
UrlAttribute |
Validates URL format |
UseLettersAttribute |
Validates that the value contains at least one letter |
📌 Usage & Best Practices
- Leverage
IActivatorfor instance creation with dependency injection. - Leverage
IAsyncActivatorfor instance creation with dependency injection in asynchronous contexts. - Utilize
IJsonDifferfor tracking JSON changes in PATCH requests. - Implement custom validation logic by extending provided base validator classes.
- Implement
IAttributeValidatorcustom for attribute-driven validation scenarios. - Simplified attribut-based validation by the
IAttributeValidatorinterface. - Use IDynamoTypeConverter or IAsyncDynamoTypeConverter to encapsulate DynamoDB-safe conversions.
- Register custom converters and provide an implementation of IDynamoEntityMapper to centralize conversion logic.
📚 Documentation
Additional details and examples are available in the repository documentation and upcoming online resources.
📢 Contributing
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 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. |
-
net10.0
- Amazon.Lambda.AspNetCoreServer.Hosting (>= 1.10.0)
- AngleSharp.Css (>= 0.17.0)
- Asp.Versioning.Http (>= 10.0.0)
- Asp.Versioning.Mvc.ApiExplorer (>= 10.0.0)
- AspNetCore.HealthChecks.UI.Client (>= 9.0.0)
- AWSSDK.Core (>= 4.0.7.4)
- AWSSDK.DynamoDBv2 (>= 4.0.18.6)
- AWSSDK.S3 (>= 4.0.23.6)
- AWSSDK.SecretsManager (>= 4.0.4.25)
- AWSSDK.StepFunctions (>= 4.0.3.4)
- AwsSignatureVersion4 (>= 5.1.0)
- HtmlSanitizer (>= 9.0.892)
- Microsoft.AspNetCore.Authentication.JwtBearer (>= 10.0.8)
- Microsoft.AspNetCore.OpenApi (>= 10.0.8)
- OpenTelemetry.Exporter.OpenTelemetryProtocol (>= 1.15.3)
- OpenTelemetry.Extensions.Hosting (>= 1.15.3)
- OpenTelemetry.Instrumentation.AspNetCore (>= 1.15.2)
- OpenTelemetry.Instrumentation.AWS (>= 1.15.1)
- OpenTelemetry.Instrumentation.AWSLambda (>= 1.15.1)
- OpenTelemetry.Instrumentation.Http (>= 1.15.1)
- OpenTelemetry.Instrumentation.Runtime (>= 1.15.1)
- Siemens.AspNet.ErrorHandling (>= 7.5.1)
- Siemens.AspNet.ErrorHandling.Contracts (>= 7.5.1)
- Siemens.AspNet.MinimalApi.Sdk.Contracts (>= 7.5.1)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on Siemens.AspNet.MinimalApi.Sdk:
| Package | Downloads |
|---|---|
|
Siemens.AspNet.MsTest.Sdk
Provides base classes, argument checking, and helper utilities for writing Siemens-style MSTest tests. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 7.5.1 | 1,394 | 6/2/2026 |
| 7.5.0 | 141 | 5/12/2026 |
| 7.5.0-alpha.16 | 65 | 5/18/2026 |
| 7.5.0-alpha.15 | 53 | 5/18/2026 |
| 7.5.0-alpha.12 | 53 | 5/12/2026 |
| 7.5.0-alpha.11 | 55 | 5/12/2026 |
| 7.5.0-alpha.10 | 55 | 5/12/2026 |
| 7.5.0-alpha.3 | 61 | 5/11/2026 |
| 7.4.6 | 33 | 6/2/2026 |
| 7.4.5 | 554 | 5/24/2026 |
| 7.4.4 | 41 | 5/18/2026 |
| 7.4.3 | 34 | 5/18/2026 |
| 7.4.2 | 2,493 | 5/11/2026 |
| 7.4.1 | 40 | 5/11/2026 |
| 7.4.0 | 5,996 | 5/6/2026 |
| 7.3.4 | 1,297 | 5/4/2026 |
| 7.3.3 | 947 | 5/4/2026 |
| 7.3.2 | 1,796 | 4/28/2026 |
| 7.3.1 | 2,043 | 4/24/2026 |
| 7.3.0 | 1,066 | 4/22/2026 |