Stardust.Interstellar.Rest.Annotations
5.7.1
dotnet add package Stardust.Interstellar.Rest.Annotations --version 5.7.1
NuGet\Install-Package Stardust.Interstellar.Rest.Annotations -Version 5.7.1
<PackageReference Include="Stardust.Interstellar.Rest.Annotations" Version="5.7.1" />
<PackageVersion Include="Stardust.Interstellar.Rest.Annotations" Version="5.7.1" />
<PackageReference Include="Stardust.Interstellar.Rest.Annotations" />
paket add Stardust.Interstellar.Rest.Annotations --version 5.7.1
#r "nuget: Stardust.Interstellar.Rest.Annotations, 5.7.1"
#:package Stardust.Interstellar.Rest.Annotations@5.7.1
#addin nuget:?package=Stardust.Interstellar.Rest.Annotations&version=5.7.1
#tool nuget:?package=Stardust.Interstellar.Rest.Annotations&version=5.7.1
Stardust.Interstellar.Rest.Annotations
Define once. Generate everywhere.
Core attributes for building contract-first REST APIs in .NET.
What is Stardust.Rest?
Stardust.Rest lets you define your REST API as a C# interface�then automatically generates both client proxies and server controllers. No more handwriting HttpClient boilerplate or scaffolding controllers.
[Api("api/users")]
public interface IUserService
{
[Get("{id}")]
Task<User> GetAsync([InPath] string id);
[Post]
Task<User> CreateAsync([InBody] User user);
}
That's it. Share this interface between your client and server projects. The ecosystem handles the rest.
Ecosystem Packages
| Package | What it does |
|---|---|
| Annotations | Define your API contract ? you are here |
| Client | Generate HTTP clients from interfaces |
| Server | Generate ASP.NET Core controllers from interfaces |
Why use it?
- ?? Contract-first � One interface = perfect client/server alignment
- ? Zero boilerplate � No manual HTTP code or controller scaffolding
- ??? Built-in resilience � Circuit breakers, retries, error handling
- ?? Extensible � Custom auth, headers, serialization, error handlers
Installation
dotnet add package Stardust.Interstellar.Rest.Annotations
Quick Reference
HTTP Verbs
[Get("route")] // GET request
[Post("route")] // POST request
[Put("route")] // PUT request
[Delete("route")] // DELETE request
[Patch("route")] // PATCH request
Parameter Binding
[Get("users/{id}")]
Task<User> GetUserAsync(
[InPath] string id, // URL path segment
[InQuery("page_size")] int pageSize, // Query string (?page_size=10)
[InHeader("X-Api-Key")] string apiKey, // HTTP header
[InBody] UpdateRequest request); // Request body
Route Configuration
[Api("api/v1/products")] // Base route prefix
[Api("api/users", "User Management API")] // With description
Attributes Reference
Verb Attributes
| Attribute | HTTP Method |
|---|---|
[Get] / [Get("path")] |
GET |
[Post] / [Post("path")] |
POST |
[Put] / [Put("path")] |
PUT |
[Delete] / [Delete("path")] |
DELETE |
[Patch] / [Patch("path")] |
PATCH |
[Head] / [Head("path")] |
HEAD |
[Options] / [Options("path")] |
OPTIONS |
Parameter Attributes
| Attribute | Location | Example |
|---|---|---|
[InPath] |
URL path | /users/{id} ? [InPath] string id |
[InQuery] or [InQuery("name")] |
Query string | ?filter=active |
[InHeader] or [InHeader("X-Name")] |
HTTP header | Custom headers |
[InBody] |
Request body | JSON/XML payload |
All parameter attributes support Description for OpenAPI documentation:
[InQuery("q", Description = "Search query text")] string searchQuery
Resilience Attributes
// Circuit breaker - stops calling failing services
[CircuitBreaker(threshold: 5, timeoutInMinutes: 1, resetTimeout: 2)]
// Retry with exponential backoff
[Retry(numberOfRetries: 3, retryInterval: 1000, incremetalWait: true)]
// Rate limiting
[Throttling(maxRequestsPerSecound: 10)]
Circuit Breaker Scopes
[CircuitBreaker(5, 1, 2)] // Shared (default)
[CircuitBreaker(5, 1, 2, CircuitBreakerScope.User)] // Per user
[CircuitBreaker(5, 1, 2, CircuitBreakerScope.Client)] // Per client
[CircuitBreaker(5, 1, 2, CircuitBreakerScope.UserAndClient)] // Multi-tenant
Authorization
[AuthorizeWrapper] // Require authentication
[AuthorizeWrapper(Roles = "Admin")] // Require role
[AuthorizeWrapper(Policy = "CanDelete")] // Require policy
Response Handling
[SuccessStatusCode(HttpStatusCode.Created)] // Return 201 on success
[SuccessStatusCode(HttpStatusCode.NoContent)] // Return 204 on success
API Versioning
[Api("api/users")]
[Version("1.0")]
public interface IUserServiceV1 { }
[Api("api/users")]
[Version("2.0", Deprecated = true)]
public interface IUserServiceV2 { }
OpenAPI Documentation
[Api("api/users")]
[ServiceDescription("User management", Tags = "Users", Summary = "CRUD operations")]
public interface IUserService
{
[Get("{id}", "Get user by ID")]
Task<User> GetAsync([InPath(Description = "Unique user ID")] string id);
}
Endpoint Routing Policies (.NET 6+)
[Api("api/items")]
[EndpointRoutingPolicy("SecurityHeaders")] // Apply to all endpoints
public interface IItemService
{
[Get]
[EndpointRoutingPolicy("Caching")] // Endpoint-specific
Task<List<Item>> GetItemsAsync();
}
Extensibility Interfaces
IAuthenticationHandler
Custom authentication logic:
public class BearerTokenHandler : IAuthenticationHandler
{
public void Apply(HttpRequestMessage req)
{
req.Headers.Authorization = new AuthenticationHeaderValue("Bearer", _token);
}
// ... other members
}
IHeaderHandler
Custom header processing:
public class CorrelationIdHandler : IHeaderHandler
{
public void SetHeader(HttpRequestMessage req)
{
req.Headers.Add("X-Correlation-Id", Guid.NewGuid().ToString());
}
// ... other members
}
IErrorHandler
Custom error handling:
public class CustomErrorHandler : IErrorHandler
{
public Exception ProduceClientException(
string message, HttpStatusCode statusCode,
Exception innerException, string body)
{
return new CustomApiException(message, statusCode, body);
}
}
[ErrorHandler(typeof(CustomErrorHandler))]
public interface IApiService { }
IErrorCategorizer
Control retry behavior:
public class CustomErrorCategorizer : IErrorCategorizer
{
public bool IsTransientError(Exception ex) => ex is HttpRequestException { StatusCode: HttpStatusCode.ServiceUnavailable };
}
[Retry(3, 1000, true, ErrorCategorizer = typeof(CustomErrorCategorizer))]
public interface IService { }
?? Security Considerations for Extensibility Interfaces
When implementing the extensibility interfaces, you take responsibility for certain security aspects. Follow these guidelines to ensure your implementations are secure.
?? IAuthenticationHandler Security
Your Responsibilities:
- Secure credential storage and retrieval
- Token lifecycle management (refresh, rotation, expiration)
- Protection against credential leakage
/// <summary>
/// SECURITY: Implementations must:
/// - Never hardcode credentials
/// - Use secure storage (Azure Key Vault, DPAPI, etc.)
/// - Implement proper token refresh logic
/// - Clear sensitive data from memory when possible
/// </summary>
public class SecureAuthHandler : IAuthenticationHandler
{
private readonly ISecureTokenProvider _tokenProvider;
public SecureAuthHandler(ISecureTokenProvider tokenProvider)
{
_tokenProvider = tokenProvider ?? throw new ArgumentNullException(nameof(tokenProvider));
}
public async Task ApplyAsync(HttpRequestMessage req)
{
// ? Get token from secure provider
var token = await _tokenProvider.GetTokenAsync();
if (!string.IsNullOrEmpty(token))
{
req.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
}
}
public void Apply(HttpRequestMessage req)
{
ApplyAsync(req).GetAwaiter().GetResult();
}
public void BodyData(byte[] body)
{
// For HMAC-based auth: compute signature over body
// ?? Ensure signing key is securely stored
}
}
?? Anti-patterns to avoid:
// ? DON'T: Hardcoded credentials
public class InsecureHandler : IAuthenticationHandler
{
private const string ApiKey = "sk-12345..."; // ? Never do this!
}
// ? DON'T: Plain text configuration
public class InsecureHandler : IAuthenticationHandler
{
public InsecureHandler(IConfiguration config)
{
_token = config["ApiToken"]; // ? Not secure for production
}
}
?? IHeaderHandler Security
Your Responsibilities:
- Header value sanitization (the framework handles standard headers automatically)
- Prevention of header injection attacks
- Protection of sensitive data in headers
/// <summary>
/// SECURITY: Implementations must sanitize header values to prevent injection.
/// The framework provides SanitizeHttpHeaderValue() for this purpose.
/// </summary>
public class SecureHeaderHandler : IHeaderHandler
{
public int ProcessingOrder => 0;
public void SetHeader(HttpRequestMessage req)
{
var correlationId = Activity.Current?.Id ?? Guid.NewGuid().ToString();
// ? Use only alphanumeric/dash characters in custom headers
// ? Framework automatically sanitizes standard parameter headers
req.Headers.Add("X-Correlation-Id", correlationId);
}
public void GetHeader(HttpResponseMessage response)
{
// ?? Don't log sensitive header values
// ? Validate expected header formats before use
}
}
Header Injection Prevention: The framework automatically sanitizes header names and values per RFC 7230, removing:
- CR (
\r) and LF (\n) characters - URL-encoded variants (
%0d,%0a) - Double-encoded variants (
%250d,%250a) - Unicode line separators (
\u2028,\u2029)
?? IErrorHandler Security
Your Responsibilities:
- Preventing sensitive information disclosure in error responses
- Logging errors securely (no credentials in logs)
- Providing meaningful but safe error messages to clients
/// <summary>
/// SECURITY: Error handlers must not expose:
/// - Stack traces in production
/// - Internal system details
/// - Database connection strings
/// - File paths
/// - PII (emails, SSNs, etc.)
/// </summary>
public class SecureErrorHandler : IErrorHandler
{
private readonly ILogger _logger;
private readonly bool _isDevelopment;
public SecureErrorHandler(ILogger logger, IHostEnvironment env)
{
_logger = logger;
_isDevelopment = env.IsDevelopment();
}
public Exception ProduceClientException(
string message,
HttpStatusCode statusCode,
Exception innerException,
string responseBody)
{
// ? Generate error ID for correlation
var errorId = Guid.NewGuid().ToString("N");
// ? Log full details internally
_logger.LogError(innerException, "Error {ErrorId}: {Message}", errorId, message);
// ? Return sanitized message to client
var clientMessage = _isDevelopment
? message
: $"An error occurred. Reference ID: {errorId}";
return new ApiException(clientMessage, statusCode, errorId);
}
}
?? IInputInterceptor Security
Your Responsibilities:
- Input validation before processing
- Protection against injection attacks (SQL, XSS, command injection)
- Rate limiting and request throttling
/// <summary>
/// SECURITY: Input interceptors should validate:
/// - Required fields are present
/// - Data types and formats are correct
/// - Values are within acceptable ranges
/// - No injection attack patterns
/// </summary>
public class SecureInputValidator : IInputInterceptor
{
public bool Intercept(object[] values, StateDictionary state,
out string message, out HttpStatusCode statusCode)
{
var errors = new List<string>();
foreach (var value in values.Where(v => v != null))
{
// ? Use Data Annotations validation
var context = new ValidationContext(value);
var results = new List<ValidationResult>();
if (!Validator.TryValidateObject(value, context, results, true))
{
errors.AddRange(results.Select(r => r.ErrorMessage));
}
// ? Additional security checks
if (value is string str && ContainsInjectionPattern(str))
{
errors.Add("Invalid characters in input");
}
}
if (errors.Any())
{
message = string.Join("; ", errors);
statusCode = HttpStatusCode.BadRequest;
return true; // Cancel request
}
message = null;
statusCode = HttpStatusCode.OK;
return false;
}
private bool ContainsInjectionPattern(string input)
{
// ?? This is defense-in-depth only
// ? Always use parameterized queries for database access
return input.Contains("<script", StringComparison.OrdinalIgnoreCase) ||
input.Contains("javascript:", StringComparison.OrdinalIgnoreCase);
}
}
??? ISerializer Security (XML)
Your Responsibilities:
- XXE (XML External Entity) prevention
- Denial of service protection via size limits
- Schema validation
/// <summary>
/// SECURITY: XML serializer implementations MUST:
/// - Disable DTD processing
/// - Disable external entity resolution
/// - Set maximum document size limits
/// </summary>
public class SecureXmlSerializer : ISerializer
{
public string SerializationType => "xml";
public object Deserialize(Stream stream, Type type)
{
// ? Secure XML reader settings
var settings = new XmlReaderSettings
{
DtdProcessing = DtdProcessing.Prohibit, // Prevent XXE
XmlResolver = null, // No external entities
MaxCharactersInDocument = 10_000_000, // Size limit
MaxCharactersFromEntities = 1000 // Entity expansion limit
};
using (var reader = XmlReader.Create(stream, settings))
{
var serializer = new XmlSerializer(type);
return serializer.Deserialize(reader);
}
}
// ... other members
}
Security Implementation Checklist
Before deploying implementations of extensibility interfaces:
IAuthenticationHandler:
- Credentials retrieved from secure storage
- No hardcoded secrets
- Token refresh implemented
- Sensitive data cleared from memory
IHeaderHandler:
- User input sanitized before adding to headers
- No sensitive data in custom headers
- Correlation IDs use safe formats
IErrorHandler:
- Stack traces hidden in production
- No PII in error messages
- Error IDs generated for correlation
- Full errors logged internally
IInputInterceptor:
- Required field validation
- Type and format validation
- Injection pattern detection
- Size/length limits enforced
ISerializer (XML):
- DTD processing disabled
- External entities blocked
- Document size limits set
Target Frameworks
.NET Standard 2.0 | .NET 6.0 | .NET 7.0 | .NET 8.0
License
Apache-2.0
Links
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 is compatible. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 is compatible. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. 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. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 2.1.1)
- Microsoft.Extensions.Primitives (>= 2.0.0)
- Newtonsoft.Json (>= 13.0.1)
- Stardust.Particles (>= 5.0.2)
- System.Reflection.Emit (>= 4.7.0)
- System.Reflection.Emit.ILGeneration (>= 4.7.0)
- System.Reflection.Emit.Lightweight (>= 4.7.0)
- System.Runtime (>= 4.3.0)
-
net6.0
- Microsoft.AspNetCore.Mvc.Versioning (>= 5.1.0)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 2.1.1)
- Microsoft.Extensions.Primitives (>= 2.0.0)
- Newtonsoft.Json (>= 13.0.1)
- Stardust.Particles (>= 5.0.2)
- System.Reflection.Emit (>= 4.7.0)
- System.Reflection.Emit.ILGeneration (>= 4.7.0)
- System.Reflection.Emit.Lightweight (>= 4.7.0)
- System.Runtime (>= 4.3.0)
-
net7.0
- Microsoft.AspNetCore.Mvc.Versioning (>= 5.1.0)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 2.1.1)
- Microsoft.Extensions.Primitives (>= 2.0.0)
- Newtonsoft.Json (>= 13.0.1)
- Stardust.Particles (>= 5.0.2)
- System.Reflection.Emit (>= 4.7.0)
- System.Reflection.Emit.ILGeneration (>= 4.7.0)
- System.Reflection.Emit.Lightweight (>= 4.7.0)
- System.Runtime (>= 4.3.0)
-
net8.0
- Microsoft.AspNetCore.Mvc.Versioning (>= 5.1.0)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 2.1.1)
- Microsoft.Extensions.Primitives (>= 2.0.0)
- Newtonsoft.Json (>= 13.0.1)
- Stardust.Particles (>= 5.0.2)
- System.Reflection.Emit (>= 4.7.0)
- System.Reflection.Emit.ILGeneration (>= 4.7.0)
- System.Reflection.Emit.Lightweight (>= 4.7.0)
- System.Runtime (>= 4.3.0)
NuGet packages (14)
Showing the top 5 NuGet packages that depend on Stardust.Interstellar.Rest.Annotations:
| Package | Downloads |
|---|---|
|
Stardust.Interstellar.Rest
Create rest service proxies based on decorated interfaces. |
|
|
Veracity.Services.Api
SDK for accessing Veracity MyServices and Profile api. Veracity MyServices is your access point for engagement of digital interaction with DNV GL. You will find digital services like “Rules and Standards”, digital tools such as our OnDemand hosted service “Secure File Transfer“, our collaboration solution “Meeting Places” (SharePoint) and many other services. Some of the services are open to all users (like “Rules and Standards” and “Secure File Transfer”), while other services require an invitation from a DNV GL employee |
|
|
Stardust.Interstellar.Rest.Service.AspNetCore
Create webapi controllers based on decorated interfaces. For use with aspnetcore on netcore or .net framework |
|
|
Stardust.Interstellar
Stardust servicecontainer implementation of the rest api generator. |
|
|
Stardust.Continuum.Client
Client for the continuum live log stream service |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 5.7.1 | 183 | 1/26/2026 |
| 5.7.0 | 344 | 1/6/2026 |
| 5.6.1 | 10,175 | 8/9/2024 |
| 5.6.0 | 3,645 | 3/5/2024 |
| 5.5.1 | 42,820 | 5/23/2022 |
| 5.5.0 | 3,087 | 5/16/2022 |
| 5.5.0-rc1 | 3,319 | 9/6/2021 |
| 5.0.1 | 60,374 | 4/6/2021 |
| 5.0.0 | 24,960 | 2/24/2021 |
| 5.0.0-rc1 | 4,219 | 2/16/2021 |
| 4.2.0 | 14,650 | 2/10/2020 |
| 4.1.1 | 26,493 | 8/20/2019 |
| 4.0.1 | 1,414 | 8/20/2019 |
| 4.0.0 | 9,460 | 8/5/2019 |
| 3.4.8 | 11,031 | 5/14/2019 |
| 3.4.6 | 4,602 | 2/7/2019 |
| 3.4.5 | 8,436 | 12/7/2018 |
| 3.4.3 | 3,369 | 12/3/2018 |
| 3.4.1 | 8,884 | 10/4/2018 |
| 3.4.0 | 3,639 | 10/4/2018 |
| 3.3.1 | 3,407 | 10/2/2018 |
| 3.3.0 | 4,336 | 10/1/2018 |
| 3.2.0 | 4,201 | 9/18/2018 |
| 3.1.0 | 9,254 | 6/26/2018 |
| 3.1.0-pre014 | 2,652 | 6/26/2018 |
| 3.1.0-pre013 | 1,435 | 6/25/2018 |
| 2.0.0.3 | 5,547 | 3/19/2018 |
| 2.0.0.2 | 4,594 | 3/5/2018 |
| 2.0.0.1-pre006 | 2,066 | 3/5/2018 |
| 2.0.0.1-pre005 | 2,317 | 2/23/2018 |
| 2.0.0.1-pre004 | 1,418 | 2/21/2018 |
| 2.0.0.1-pre003 | 1,218 | 2/21/2018 |
| 2.0.0.1-pre002 | 1,674 | 2/20/2018 |
| 2.0.0.1-pre001 | 1,158 | 2/20/2018 |
| 2.0.0.1-pre | 2,297 | 12/15/2017 |
| 2.0.0-pre | 4,181 | 8/29/2017 |
| 1.6.3 | 2,715 | 10/23/2017 |
| 1.6.0 | 10,355 | 3/8/2017 |
| 1.5.4 | 3,500 | 2/22/2017 |
| 1.5.3 | 1,532 | 2/20/2017 |
| 1.5.2 | 1,556 | 2/14/2017 |
| 1.5.0 | 4,968 | 1/24/2017 |
| 1.4.3 | 1,793 | 1/9/2017 |
| 1.4.2 | 1,591 | 12/29/2016 |
| 1.4.1.1 | 1,475 | 12/20/2016 |
| 1.4.1 | 6,935 | 11/30/2016 |
| 1.4.0 | 2,769 | 11/23/2016 |
| 1.3.1 | 13,922 | 8/18/2016 |
| 1.3.0 | 4,259 | 8/18/2016 |
| 1.2.6 | 6,490 | 6/24/2016 |
| 1.2.5 | 1,503 | 6/22/2016 |
| 1.2.4 | 1,465 | 6/22/2016 |
| 1.2.3 | 1,455 | 6/22/2016 |
| 1.2.2 | 1,489 | 6/22/2016 |
| 1.2.1 | 1,479 | 6/22/2016 |
| 1.2.0 | 5,968 | 6/14/2016 |
| 1.1.1 | 1,507 | 6/3/2016 |
| 1.1.0 | 12,220 | 6/2/2016 |
| 1.0.0.1 | 4,830 | 5/31/2016 |
Added Service Description options to Verb attributes