- For simple tasks, prefer AutoQuery.
- When tasks become complex, use a custom service.
- No need to manually register services or handle any auto wire-up - ServiceStack takes care of this automatically.
- Always provide complete code statements - never give partial code snippets.
- Create DTOs (Data Transfer Objects) for each service.
- Follow REST patterns when designing endpoints.
- Always assign routes to services.
- Consider authentication requirements for each route based on the provided information.
- Every service endpoint must have both a request DTO and a response DTO.
- Implement AutoQuery for simple CRUD operations and basic querying needs.
- Utilize AutoQuery attributes and conventions to minimize boilerplate code.
- Implement custom services for complex business logic, multi-step processes, or operations that don't fit the AutoQuery model.
- Ensure services are focused and adhere to single responsibility principle.
- Remember that ServiceStack automatically discovers and registers your services - no manual registration required.
- Use clear, descriptive names for DTOs that reflect their purpose.
- Design routes following REST conventions:
- GET for retrieving data
- POST for creating new resources
- PUT for updating existing resources
- DELETE for removing resources
- Use appropriate HTTP status codes in responses.
- For each service endpoint:
- Create a request DTO to define the input parameters
- Create a response DTO to define the structure of the returned data
-
ID Fields:
- Always apply [PrimaryKey] attribute to ID fields
- Always use [AutoIncrement] with [PrimaryKey] unless explicitly specified otherwise
-
Foreign Key Fields:
- When using [ForeignKey] attribute, always specify appropriate options (e.g., OnDelete, OnUpdate)
- Always add a [Ref(typeof(ReferencedType))] decorator alongside the [ForeignKey] attribute
- Include a corresponding Reference property for each foreign key
- Example:
[ForeignKey(typeof(Category), OnDelete = "CASCADE")] [Ref(typeof(Category))] public int CategoryId { get; set; } [Reference] public Category Category { get; set; }
-
String Fields:
- Try to determine an appropriate length and use [StringLength(n)] where possible
- If unsure, use [MaxLength(n)] with a reasonable maximum length
-
Decimal Fields:
- Set decimal precision using [DecimalLength(precision, scale)]
- Apply any other relevant decorators for decimal fields
-
Validation Attributes: When implementing validation, prioritize using the following specific attributes before resorting to the general
[Validate]attribute or custom validation:public class ExampleValidators : ICreateDb<ExampleValidator>, IReturn<EmptyResponse> { [ValidateCreditCard] public string CreditCard { get; set; } [ValidateEmail] public string Email { get; set; } [ValidateEmpty] public string Empty { get; set; } [ValidateEqual("Equal")] public string Equal { get; set; } [ValidateLessThan(10)] public int LessThan { get; set; } [ValidateLessThanOrEqual(10)] public int LessThanOrEqual { get; set; } [ValidateGreaterThan(10)] public int GreaterThan { get; set; } [ValidateGreaterThanOrEqual(10)] public int GreaterThanOrEqual { get; set; } [ValidateExclusiveBetween(10, 20)] public int ExclusiveBetween { get; set; } [ValidateInclusiveBetween(10, 20)] public int InclusiveBetween { get; set; } [ValidateExactLength(10)] public string Length { get; set; } [ValidateNotEmpty] public string NotEmpty { get; set; } [ValidateNotEqual("NotEqual")] public string NotEqual { get; set; } [ValidateNull] public string Null { get; set; } [ValidateScalePrecision(1,1)] public decimal ScalePrecision { get; set; } [ValidateRegularExpression("^[a-z]*$")] public string RegularExpression { get; set; } }
If the specific validation attributes don't meet your needs, you can use the general
[Validate]attribute with a validation expression. Here are examples:public class ExampleValidators : ICreateDb<ExampleValidator>, IReturn<EmptyResponse> { [Validate("CreditCard")] public string CreditCard { get; set; } [Validate("Email")] public string Email { get; set; } [Validate("Empty")] public string Empty { get; set; } [Validate("Equal('Equal')")] public string Equal { get; set; } [Validate("ExclusiveBetween(10, 20)")] public int ExclusiveBetween { get; set; } [Validate("GreaterThanOrEqual(10)")] public int GreaterThanOrEqual { get; set; } [Validate("GreaterThan(10)")] public int GreaterThan { get; set; } [Validate("InclusiveBetween(10, 20)")] public int InclusiveBetween { get; set; } [Validate("ExactLength(10)")] public string Length { get; set; } [Validate("LessThanOrEqual(10)")] public int LessThanOrEqual { get; set; } [Validate("LessThan(10)")] public int LessThan { get; set; } [Validate("NotEmpty")] public string NotEmpty { get; set; } [Validate("NotEqual('NotEqual')")] public string NotEqual { get; set; } [Validate("Null")] public string Null { get; set; } [Validate("RegularExpression('^[a-z]*$')")] public string RegularExpression { get; set; } [Validate("ScalePrecision(1,1)")] public decimal ScalePrecision { get; set; } }
Request Validation Attributes:
- [ValidateRequest]: General request validation
- [ValidateIsAuthenticated]: Protect access to API for Authenticated Users only
- [ValidateIsAdmin]: Protect access to API for Admin Users only
- [ValidateHasPermission]: Protect access to API for Users with ALL specified Permissions
- [ValidateHasRole]: Protect access to API for Users with ALL specified Roles
-
General Practice:
- Always consider the nature of the data and apply the most appropriate validation decorators
- Use multiple decorators when necessary to ensure comprehensive validation
- When in doubt about which decorator to use, consult the Excel spreadsheets
- Provide complete code statements - never give partial code snippets
- Prefer specific validation attributes when possible
- Use the general
[Validate]attribute with appropriate expressions when specific attributes are not suitable - Resort to custom validation logic only when neither specific attributes nor the general
[Validate]attribute can meet the requirements
- Evaluate each route to determine if it requires authentication.
- Apply authentication attributes as necessary (e.g.,
[Authenticate],[RequiredRole("Admin")]).
- Refer to the provided Excel files for the complete list of available decorators.
- Apply relevant decorators to DTOs and services to enhance functionality and maintain consistency.
- Regularly review the Excel files to stay updated on available decorators.
When implementing rate limiting for your ServiceStack application, especially for SaaS applications with per-user rate limiting, refer to the official ServiceStack documentation:
https://docs.servicestack.net/rate-limiting#per-user-rate-limiting-for-saas-applications
Key points to consider:
- ServiceStack provides built-in support for rate limiting.
- You can configure global rate limits or per-user rate limits.
- Rate limits can be set based on various time intervals (per second, minute, hour, day).
- For SaaS applications, consider implementing per-user rate limiting to ensure fair usage across your user base.
- The documentation provides examples of how to configure and customize rate limiting for your specific needs.
Always consult the official documentation for the most up-to-date information and best practices regarding rate limiting in ServiceStack.
- Keep services and DTOs in separate files for better organization.
- Use meaningful names for services, DTOs, and their properties.
- Include XML comments for public APIs to improve documentation.
- Implement proper error handling and validation in services.
- Use dependency injection where appropriate to manage service dependencies.
- Ensure that request and response DTOs are properly paired for each service endpoint.
- Apply field-specific attributes and validation consistently across all DTOs.
- Regularly consult the Excel spreadsheets for the most up-to-date list of decorators and their usage.
- Trust ServiceStack's auto-discovery and registration - no need to manually register services or configure wire-up.
- When using foreign keys, always include both [ForeignKey] and [Ref] attributes, and add a corresponding Reference property.
- Use the provided validation attributes whenever possible before resorting to custom validation logic.
- Always provide complete code statements, never partial snippets.
- Use specific validation attributes whenever possible
- Use the general
[Validate]attribute with appropriate expressions when specific attributes are not suitable - Resort to custom validation logic only when neither specific attributes nor the general
[Validate]attribute can meet the requirements - Implement appropriate rate limiting for your APIs, especially for SaaS applications.
- Regularly review and adjust rate limits based on your application's needs and user behavior.
- AutoQuery used for simple tasks
- Custom services implemented for complex logic
- DTOs created and properly structured
- Each service endpoint has both request and response DTOs
- REST patterns followed in route design
- Routes assigned to all services
- Authentication considered and implemented where necessary
- Appropriate decorators applied (as per Excel spreadsheets)
- ID fields have [PrimaryKey] and [AutoIncrement] attributes (unless specified otherwise)
- String fields use [StringLength] or [MaxLength] appropriately
- Decimal fields have proper precision set
- Validation decorators applied based on field names and purposes
- Excel spreadsheets consulted for most recent decorator information
- Code is clean, readable, and well-commented
- Error handling and input validation implemented
- Request and response DTOs are logically paired for each endpoint
- No unnecessary manual service registration or wire-up code present
- Foreign key fields have [ForeignKey] attribute with appropriate options
- [Ref] decorator is used alongside [ForeignKey] attributes
- Reference properties are included for all foreign keys
- Appropriate validation attributes are used for each field
- Custom validation is only used when necessary
- All code snippets and examples are complete, not partial
- Specific validation attributes are used where applicable
- General
[Validate]attribute is used appropriately when specific attributes are not suitable - Custom validation is only used when absolutely necessary
- All validation expressions in
[Validate]attributes are correct and follow ServiceStack conventions - Rate limiting is implemented where necessary
- Per-user rate limiting is considered for SaaS applications
- Rate limits are appropriate for the application's requirements