![]() |
VOOZH | about |
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" />Directory.Packages.props
<PackageReference Include="Stardust.Interstellar.Rest.Annotations" />Project file
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.1Install as a Cake Addin
#tool nuget:?package=Stardust.Interstellar.Rest.Annotations&version=5.7.1Install as a Cake Tool
Define once. Generate everywhere.
Core attributes for building contract-first REST APIs in .NET.
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.
| 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 |
dotnet add package Stardust.Interstellar.Rest.Annotations
[Get("route")] // GET request
[Post("route")] // POST request
[Put("route")] // PUT request
[Delete("route")] // DELETE request
[Patch("route")] // PATCH request
[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
[Api("api/v1/products")] // Base route prefix
[Api("api/users", "User Management API")] // With description
| 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 |
| 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
// 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)]
[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
[AuthorizeWrapper] // Require authentication
[AuthorizeWrapper(Roles = "Admin")] // Require role
[AuthorizeWrapper(Policy = "CanDelete")] // Require policy
[SuccessStatusCode(HttpStatusCode.Created)] // Return 201 on success
[SuccessStatusCode(HttpStatusCode.NoContent)] // Return 204 on success
[Api("api/users")]
[Version("1.0")]
public interface IUserServiceV1 { }
[Api("api/users")]
[Version("2.0", Deprecated = true)]
public interface IUserServiceV2 { }
[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);
}
[Api("api/items")]
[EndpointRoutingPolicy("SecurityHeaders")] // Apply to all endpoints
public interface IItemService
{
[Get]
[EndpointRoutingPolicy("Caching")] // Endpoint-specific
Task<List<Item>> GetItemsAsync();
}
Custom authentication logic:
public class BearerTokenHandler : IAuthenticationHandler
{
public void Apply(HttpRequestMessage req)
{
req.Headers.Authorization = new AuthenticationHeaderValue("Bearer", _token);
}
// ... other members
}
Custom header processing:
public class CorrelationIdHandler : IHeaderHandler
{
public void SetHeader(HttpRequestMessage req)
{
req.Headers.Add("X-Correlation-Id", Guid.NewGuid().ToString());
}
// ... other members
}
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 { }
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 { }
When implementing the extensibility interfaces, you take responsibility for certain security aspects. Follow these guidelines to ensure your implementations are secure.
Your Responsibilities:
/// <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
}
}
Your Responsibilities:
/// <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:
\r) and LF (\n) characters%0d, %0a)%250d, %250a)\u2028, \u2029)Your Responsibilities:
/// <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);
}
}
Your Responsibilities:
/// <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);
}
}
Your Responsibilities:
/// <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
}
Before deploying implementations of extensibility interfaces:
IAuthenticationHandler:
IHeaderHandler:
IErrorHandler:
IInputInterceptor:
ISerializer (XML):
.NET Standard 2.0 | .NET 6.0 | .NET 7.0 | .NET 8.0
Apache-2.0
| 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 is compatible. 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 is compatible. 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 is compatible. 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 was computed. 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 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.Continuum.Client
Client for the continuum live log stream service |
|
|
Stardust.Interstellar
Stardust servicecontainer implementation of the rest api generator. |
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 5.7.1 | 2,569 | 1/26/2026 |
| 5.7.0 | 926 | 1/6/2026 |
| 5.6.1 | 14,374 | 8/9/2024 |
| 5.6.0 | 3,863 | 3/5/2024 |
| 5.5.1 | 46,994 | 5/23/2022 |
| 5.5.0 | 3,119 | 5/16/2022 |
| 5.5.0-rc1 | 3,345 | 9/6/2021 |
| 5.0.1 | 61,637 | 4/6/2021 |
| 5.0.0 | 26,785 | 2/24/2021 |
| 5.0.0-rc1 | 4,270 | 2/16/2021 |
| 4.2.0 | 14,732 | 2/10/2020 |
| 4.1.1 | 26,595 | 8/20/2019 |
| 4.0.1 | 1,445 | 8/20/2019 |
| 4.0.0 | 9,515 | 8/5/2019 |
| 3.4.8 | 11,068 | 5/14/2019 |
| 3.4.6 | 4,631 | 2/7/2019 |
| 3.4.5 | 8,460 | 12/7/2018 |
| 3.4.3 | 3,432 | 12/3/2018 |
Added Service Description options to Verb attributes