Stardust.Interstellar.Rest.Service.AspNetCore
5.7.1
dotnet add package Stardust.Interstellar.Rest.Service.AspNetCore --version 5.7.1
NuGet\Install-Package Stardust.Interstellar.Rest.Service.AspNetCore -Version 5.7.1
<PackageReference Include="Stardust.Interstellar.Rest.Service.AspNetCore" Version="5.7.1" />
<PackageVersion Include="Stardust.Interstellar.Rest.Service.AspNetCore" Version="5.7.1" />
<PackageReference Include="Stardust.Interstellar.Rest.Service.AspNetCore" />
paket add Stardust.Interstellar.Rest.Service.AspNetCore --version 5.7.1
#r "nuget: Stardust.Interstellar.Rest.Service.AspNetCore, 5.7.1"
#:package Stardust.Interstellar.Rest.Service.AspNetCore@5.7.1
#addin nuget:?package=Stardust.Interstellar.Rest.Service.AspNetCore&version=5.7.1
#tool nuget:?package=Stardust.Interstellar.Rest.Service.AspNetCore&version=5.7.1
Stardust.Interstellar.Rest.Service.AspNetCore
Define once. Generate everywhere.
Generate ASP.NET Core controllers and endpoints from decorated interfaces.
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 |
| Client | Generate HTTP clients from interfaces |
| Server | Generate ASP.NET Core controllers from interfaces β you are here |
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.Service.AspNetCore
Quick Start
1. Define your interface
using Stardust.Interstellar.Rest.Annotations;
[Api("api/users")]
public interface IUserService
{
[Get("{id}")]
Task<User> GetUserAsync([InPath] string id);
[Get]
Task<IEnumerable<User>> GetAllAsync();
[Post]
Task<User> CreateAsync([InBody] User user);
}
2. Implement the service
public class UserService : IUserService
{
private readonly IUserRepository _repo;
public UserService(IUserRepository repo) => _repo = repo;
public Task<User> GetUserAsync(string id) => _repo.GetByIdAsync(id);
public Task<IEnumerable<User>> GetAllAsync() => _repo.GetAllAsync();
public Task<User> CreateAsync(User user) => _repo.CreateAsync(user);
}
3. Register as controller
services.AddInterstellar();
services.AddMvc()
.AddAsController<IUserService, UserService>()
.UseInterstellar(); // Don't forget this!
4. Map routes
app.UseRouting();
app.UseEndpoints(endpoints => endpoints.MapControllers());
Registration Options
MVC Controllers
services.AddMvc()
// With implementation type
.AddAsController<IUserService, UserService>()
// Or if already in DI
.AddAsController<IProductService>()
// Or with factory
.AddAsController<IOrderService>(sp => new OrderService(sp.GetRequiredService<IOrderRepo>()))
// Always call UseInterstellar() at the end
.UseInterstellar();
Minimal API Endpoints (.NET 6+)
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddInterstellar();
builder.Services.AddScoped<IUserService, UserService>();
var app = builder.Build();
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.AddAsEndpoints<IUserService>();
});
app.Run();
Proxy Controller
Forward requests to another service:
services.AddMvc()
.AddProxyController<IExternalService>("https://api.external.com")
.UseInterstellar();
Parameter Binding
Parameters are automatically bound with proper ASP.NET Core attributes:
[Get("search")]
Task<SearchResult> SearchAsync(
[InQuery("q")] string searchQuery, // [FromQuery(Name = "q")]
[InQuery("page_size")] int pageSize, // [FromQuery(Name = "page_size")]
[InHeader("X-Api-Key")] string apiKey); // [FromHeader(Name = "X-Api-Key")]
[Post]
Task<User> CreateAsync([InBody] User user); // [FromBody]
[Get("users/{id}")]
Task<User> GetAsync([InPath] string id); // [FromRoute]
Authorization
Interface-level
[Api("api/admin")]
[AuthorizeWrapper(Roles = "Admin")]
public interface IAdminService { }
Method-level
[Api("api/users")]
public interface IUserService
{
[Get]
Task<IEnumerable<User>> GetAllAsync();
[Delete("{id}")]
[AuthorizeWrapper(Policy = "CanDelete")]
Task DeleteAsync([InPath] string id);
}
Response Status Codes
[Post]
[SuccessStatusCode(HttpStatusCode.Created)]
Task<User> CreateAsync([InBody] User user);
[Delete("{id}")]
[SuccessStatusCode(HttpStatusCode.NoContent)]
Task DeleteAsync([InPath] string id);
API Versioning
[Api("api/users")]
[Version("1.0")]
public interface IUserServiceV1 { }
[Api("api/users")]
[Version("2.0")]
public interface IUserServiceV2 { }
Configure with Microsoft.AspNetCore.Mvc.Versioning:
services.AddApiVersioning(options =>
{
options.DefaultApiVersion = new ApiVersion(1, 0);
options.AssumeDefaultVersionWhenUnspecified = true;
});
services.AddMvc()
.AddAsController<IUserServiceV1, UserServiceV1>()
.AddAsController<IUserServiceV2, UserServiceV2>()
.UseInterstellar();
OpenAPI / Swagger
Generated controllers work with Swashbuckle out of the box:
[Api("api/users")]
[ServiceDescription("User management", Tags = "Users")]
public interface IUserService
{
[Get("{id}", "Get user by ID")]
Task<User> GetAsync([InPath(Description = "Unique user ID")] string id);
[Get("search", "Search users")]
Task<List<User>> SearchAsync(
[InQuery("q", Description = "Search query")] string query,
[InQuery("page_size", Description = "Results per page")] int pageSize);
}
Endpoint Routing Policies (.NET 6+)
Apply custom policies to minimal API endpoints:
public class CachingPolicy : IEndpointRoutingPolicy
{
public string PolicyName => "Caching";
public void ApplyPolicyAsync(RouteHandlerBuilder builder) { /* ... */ }
public Dictionary<string, string> GetResponseHeaders()
=> new() { ["Cache-Control"] = "public, max-age=300" };
}
// Register
services.AddSingleton<IEndpointRoutingPolicy>(new CachingPolicy());
// Apply
[Api("api/items")]
[EndpointRoutingPolicy("SecurityHeaders")] // All endpoints
public interface IItemService
{
[Get]
[EndpointRoutingPolicy("Caching")] // This endpoint only
Task<List<Item>> GetItemsAsync();
}
Service Initialization
Perform setup when the service is instantiated:
public class UserService : IUserService, IInitializableService
{
public void Initialize(StateDictionary state, object[] parameters)
{
// Called before method execution
}
}
Contract-First Architecture
Share interfaces between client and server:
MyApi.Contracts/ β Shared library
βββ IUserService.cs
βββ IProductService.cs
βββ Models/
βββ User.cs
MyApi.Server/ β Uses this package
βββ References MyApi.Contracts
βββ Implements services
MyApi.Client/ β Uses Stardust.Interstellar.Rest
βββ References MyApi.Contracts
βββ Consumes services via proxy
Configuration
// Debug mode - throws during generation
ServiceFactory.ThrowOnException = true;
// Disable version header
ServiceFactory.DisableStardustVersion();
π Security Considerations
The server library generates ASP.NET Core controllers and endpoints from your interfaces. Several security aspects require developer attention.
Built-in Security Features
| Feature | Status | Description |
|---|---|---|
| HTTP Header Sanitization | β Built-in | Response headers are automatically sanitized |
| ASP.NET Core Integration | β Built-in | Leverages ASP.NET Core's security infrastructure |
| Authorization Support | β Built-in | [AuthorizeWrapper] maps to ASP.NET Core authorization |
| Model Binding | β Built-in | Uses ASP.NET Core's secure model binding |
Developer Responsibilities
π¨ Error Handling & Information Disclosure
By default, exception messages may be exposed to clients. Implement a secure error handler:
public class SecureErrorHandler : IErrorHandler
{
private readonly ILogger<SecureErrorHandler> _logger;
private readonly IHostEnvironment _env;
public SecureErrorHandler(ILogger<SecureErrorHandler> logger, IHostEnvironment env)
{
_logger = logger;
_env = env;
}
public HttpResponseMessage ConvertToErrorResponse(Exception ex, HttpRequestMessage req)
{
// β
Generate unique error ID for correlation
var errorId = Guid.NewGuid().ToString("N");
// β
Log full exception internally
_logger.LogError(ex, "Error {ErrorId} processing {Method} {Path}",
errorId, req.Method, req.RequestUri?.PathAndQuery);
// β
Return sanitized response based on environment
var response = new ErrorResponse
{
ErrorId = errorId,
Message = _env.IsDevelopment()
? ex.Message
: "An error occurred processing your request.",
// β Never include: ex.StackTrace, ex.InnerException, connection strings
};
return req.CreateResponse(GetStatusCode(ex), response);
}
private HttpStatusCode GetStatusCode(Exception ex) => ex switch
{
ArgumentException => HttpStatusCode.BadRequest,
UnauthorizedAccessException => HttpStatusCode.Unauthorized,
KeyNotFoundException => HttpStatusCode.NotFound,
_ => HttpStatusCode.InternalServerError
};
}
// Register globally
services.AddScoped<IErrorHandler, SecureErrorHandler>();
β οΈ Information Disclosure Risks:
- β Stack traces reveal internal structure
- β Exception messages may contain file paths
- β Database errors may expose connection strings
- β Validation errors may reveal expected formats
π Authorization Best Practices
Use ASP.NET Core's authorization system with [AuthorizeWrapper]:
[Api("api/admin")]
[AuthorizeWrapper(Roles = "Admin")] // Require Admin role for all methods
public interface IAdminService
{
[Get("users")]
Task<List<User>> GetAllUsersAsync();
[Delete("users/{id}")]
[AuthorizeWrapper(Policy = "SuperAdmin")] // Additional policy requirement
Task DeleteUserAsync([InPath] string id);
}
Configure authorization:
services.AddAuthorization(options =>
{
options.AddPolicy("SuperAdmin", policy =>
policy.RequireRole("Admin")
.RequireClaim("department", "IT"));
});
// Require authentication by default
services.AddAuthorization(options =>
{
options.FallbackPolicy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
});
π‘οΈ Input Validation
Implement input validation using IInputInterceptor or ASP.NET Core model validation:
// Option 1: Use Data Annotations on your models
public class CreateUserRequest
{
[Required]
[StringLength(100, MinimumLength = 1)]
public string Name { get; set; }
[Required]
[EmailAddress]
public string Email { get; set; }
[Range(0, 150)]
public int? Age { get; set; }
}
// Option 2: Custom input interceptor
public class ValidationInterceptor : IInputInterceptor
{
public bool Intercept(object[] values, StateDictionary state,
out string message, out HttpStatusCode statusCode)
{
foreach (var value in values.Where(v => v != null))
{
var context = new ValidationContext(value);
var results = new List<ValidationResult>();
if (!Validator.TryValidateObject(value, context, results, true))
{
message = string.Join("; ", results.Select(r => r.ErrorMessage));
statusCode = HttpStatusCode.BadRequest;
return true; // Cancel request
}
}
message = null;
statusCode = HttpStatusCode.OK;
return false;
}
}
// Apply to interface
[InputInterceptor(typeof(ValidationInterceptor))]
public interface IUserService { }
β±οΈ Rate Limiting
Protect against DoS attacks using the built-in throttling:
// Interface-level rate limiting
[Api("api/users")]
[Throttling(maxRequestsPerSecound: 100)]
public interface IUserService { }
// Method-level (more restrictive for expensive operations)
[Api("api/reports")]
public interface IReportService
{
[Get]
[Throttling(maxRequestsPerSecound: 10)] // Expensive operation
Task<Report> GenerateReportAsync([InQuery] ReportRequest request);
}
β οΈ Limitations:
- Built-in throttling is in-memory only
- For distributed environments, use ASP.NET Core Rate Limiting or a custom
IThrottlingManager
// .NET 7+ Rate Limiting Middleware (recommended for production)
builder.Services.AddRateLimiter(options =>
{
options.GlobalLimiter = PartitionedRateLimiter.Create<HttpContext, string>(context =>
RateLimitPartition.GetFixedWindowLimiter(
partitionKey: context.User.Identity?.Name ?? context.Connection.RemoteIpAddress?.ToString() ?? "anonymous",
factory: _ => new FixedWindowRateLimiterOptions
{
Window = TimeSpan.FromSeconds(1),
PermitLimit = 100
}));
});
app.UseRateLimiter();
π Response Header Security
Add security headers using endpoint routing policies:
public class SecurityHeadersPolicy : IEndpointRoutingPolicy
{
public string PolicyName => "SecurityHeaders";
public void ApplyPolicyAsync(RouteHandlerBuilder builder)
{
builder.AddEndpointFilter(async (context, next) =>
{
var result = await next(context);
var response = context.HttpContext.Response;
response.Headers["X-Content-Type-Options"] = "nosniff";
response.Headers["X-Frame-Options"] = "DENY";
response.Headers["X-XSS-Protection"] = "1; mode=block";
response.Headers["Referrer-Policy"] = "strict-origin-when-cross-origin";
return result;
});
}
public Dictionary<string, string> GetResponseHeaders() => new()
{
["X-Content-Type-Options"] = "nosniff",
["X-Frame-Options"] = "DENY"
};
}
// Apply to all endpoints
[Api("api/users")]
[EndpointRoutingPolicy("SecurityHeaders")]
public interface IUserService { }
π Logging & Auditing
Implement proper logging without exposing sensitive data:
public class AuditingHeaderHandler : IHeaderHandler
{
private readonly ILogger _logger;
public int ProcessingOrder => int.MaxValue; // Run last
public void SetHeader(HttpRequestMessage req)
{
// Add correlation ID for tracing
var correlationId = Activity.Current?.Id ?? Guid.NewGuid().ToString();
req.Headers.Add("X-Correlation-Id", correlationId);
}
public void GetHeader(HttpResponseMessage response)
{
// β
Log request completion
// β Don't log: Authorization headers, request bodies with PII
_logger.LogInformation(
"Request completed: {Method} {Path} -> {StatusCode}",
response.RequestMessage?.Method,
response.RequestMessage?.RequestUri?.PathAndQuery,
response.StatusCode);
}
}
Security Configuration Checklist
Error Handling:
- Custom
IErrorHandlerimplemented - Stack traces hidden in production
- Error IDs generated for correlation
- Sensitive data scrubbed from messages
Authorization:
-
[AuthorizeWrapper]applied appropriately - Policies configured for sensitive operations
- Default deny policy considered
Input Validation:
- Data Annotations on request models
- Custom
IInputInterceptorfor complex validation - Size limits on request bodies
Rate Limiting:
-
[Throttling]applied to public endpoints - Distributed rate limiting for scaled deployments
- Different limits for different operations
Response Security:
- Security headers added
- CORS configured appropriately
- Sensitive data not in responses
Full Example
// Program.cs (.NET 6+)
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddInterstellar();
builder.Services.AddScoped<IUserService, UserService>();
builder.Services.AddScoped<IProductService, ProductService>();
// Security: Add error handler
builder.Services.AddScoped<IErrorHandler, SecureErrorHandler>();
builder.Services.AddMvc()
.AddAsController<IUserService, UserService>()
.UseInterstellar();
builder.Services.AddSwaggerGen();
// Security: Add authorization
builder.Services.AddAuthorization();
// Security: Add rate limiting (.NET 7+)
builder.Services.AddRateLimiter(options => { /* ... */ });
var app = builder.Build();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseRateLimiter();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.AddAsEndpoints<IProductService>();
});
app.UseSwagger();
app.UseSwaggerUI();
app.Run();
Target Frameworks
.NET Standard 2.0 | .NET Core 3.1 | .NET 5.0 | .NET 6.0 | .NET 7.0 | .NET 8.0
Dependencies
- Stardust.Interstellar.Rest.Annotations
- Stardust.Interstellar.Rest
- Microsoft.AspNetCore.Mvc.Versioning
License
Apache-2.0
Links
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 is compatible. 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 is compatible. |
| .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. |
-
.NETCoreApp 3.1
- Microsoft.AspNetCore.Mvc.Versioning (>= 4.1.1)
- Microsoft.Extensions.Primitives (>= 3.1.1)
- Stardust.Interstellar.Rest (>= 5.7.2)
- Stardust.Interstellar.Rest.Annotations (>= 5.7.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)
-
.NETStandard 2.0
- Microsoft.AspNetCore (>= 2.0.2)
- Microsoft.AspNetCore.Mvc (>= 2.0.2)
- Microsoft.AspNetCore.Mvc.Core (>= 2.0.2)
- Microsoft.AspNetCore.Mvc.Versioning (>= 2.0.0)
- Microsoft.Extensions.Primitives (>= 2.1.1)
- Stardust.Interstellar.Rest (>= 5.7.2)
- Stardust.Interstellar.Rest.Annotations (>= 5.7.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)
-
net5.0
- Microsoft.AspNetCore.Mvc.Versioning (>= 5.1.0)
- Microsoft.Extensions.Primitives (>= 5.0.1)
- Stardust.Interstellar.Rest (>= 5.7.2)
- Stardust.Interstellar.Rest.Annotations (>= 5.7.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)
-
net6.0
- Microsoft.AspNetCore.Mvc.Versioning (>= 5.1.0)
- Microsoft.Extensions.Primitives (>= 6.0.0)
- Stardust.Interstellar.Rest (>= 5.7.2)
- Stardust.Interstellar.Rest.Annotations (>= 5.7.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)
-
net7.0
- Microsoft.AspNetCore.Mvc.Versioning (>= 5.1.0)
- Microsoft.Extensions.Primitives (>= 7.0.0)
- Stardust.Interstellar.Rest (>= 5.7.2)
- Stardust.Interstellar.Rest.Annotations (>= 5.7.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)
-
net8.0
- Microsoft.AspNetCore.Mvc.Versioning (>= 5.1.0)
- Microsoft.Extensions.Primitives (>= 8.0.0)
- Stardust.Interstellar.Rest (>= 5.7.2)
- Stardust.Interstellar.Rest.Annotations (>= 5.7.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)
NuGet packages (2)
Showing the top 2 NuGet packages that depend on Stardust.Interstellar.Rest.Service.AspNetCore:
| Package | Downloads |
|---|---|
|
Stardust.Interstellar.Rest.Service
Deprecated, this is only for ease of migration Create webapi controllers based on decorated interfaces. |
|
|
Veracity.Common.OAuth.AspNetCore
Authentication library for the veracity services sdk for aspnetcore |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 5.7.1 | 75 | 1/26/2026 |
| 5.7.0 | 116 | 1/6/2026 |
| 5.6.1 | 4,528 | 5/3/2024 |
| 5.6.0 | 250 | 3/5/2024 |
| 5.5.4 | 26,673 | 8/24/2022 |
| 5.5.3 | 3,490 | 5/23/2022 |
| 5.5.2 | 746 | 5/21/2022 |
| 5.5.1 | 828 | 5/16/2022 |
| 5.5.0-rc2 | 872 | 9/24/2021 |
| 5.5.0-rc1 | 1,186 | 9/6/2021 |
| 5.0.1 | 45,438 | 4/6/2021 |
| 5.0.0 | 7,863 | 2/24/2021 |
| 5.0.0-rc1 | 608 | 2/16/2021 |
| 4.2.1 | 1,011 | 11/13/2020 |
| 4.2.0 | 3,815 | 2/10/2020 |
| 4.1.0 | 12,693 | 8/20/2019 |
| 4.0.1 | 912 | 8/7/2019 |
| 4.0.0 | 2,943 | 8/5/2019 |
Fixed version issue with Microsoft.AspNetCore.Mvc.Versioning