Coding Standards¶
This document provides coding standards and guidelines for developers and AI code generators working on ConnectSoft projects. Rather than duplicating comprehensive rule sets, this document references established analyzer repositories and highlights key rules that are particularly important for maintaining code quality and consistency.
Primary References¶
The following analyzer repositories provide comprehensive rule sets and should be referenced for detailed guidelines:
-
StyleCopAnalyzers: Implementation of StyleCop rules using the .NET Compiler Platform (Roslyn). Provides code style and consistency rules for C# code. See the documentation for a complete list of rules.
-
AspNetCoreAnalyzers: Analyzers for ASP.NET Core applications that identify best practices and potential issues specific to web development.
-
DocumentationAnalyzers: Analyzers that improve the quality of XML documentation comments in C# code, ensuring proper documentation standards.
Naming Conventions¶
"There are only two hard things in Computer Science: cache invalidation and naming things."
— Phil Karlton
Consistent naming conventions help maintain clarity, readability, and maintainability of the codebase. The following guidelines outline the standards used in ConnectSoft projects. These conventions follow Microsoft .NET Framework Design Guidelines while incorporating domain-driven design and Clean Architecture principles.
Test Methods¶
- Test names should NOT contain underscores: Use descriptive names with proper casing instead of underscores.
- ✅ Good:
ShouldReturnUserWhenIdIsValid(),CanProcessOrderWithValidItems() - ❌ Bad:
Should_Return_User_When_Id_Is_Valid(),Can_Process_Order_With_Valid_Items()
General Naming Conventions¶
Case Styles¶
| Case Style | Usage | Example |
|---|---|---|
| PascalCase | Classes, methods, properties, namespaces, constants, enums | UserService, GetUserInfo, OrderDetails, MaxRetries |
| camelCase | Variables, parameters, private fields | userName, totalAmount, logger |
| UPPER_CASE | Rarely used (only for very specific constants or legacy code) | Not recommended |
Abbreviations¶
- Avoid abbreviations unless widely accepted
- Accepted abbreviations:
Id,Http,Https,Xml,Json,Api,Uri,Url,Db,Di,UI,IO - Avoid:
Usr,Ord,Cust,Mgr(use full words:User,Order,Customer,Manager)
One Class Per File¶
Each class, interface, enum, or struct should be in its own file with a matching filename.
// ✅ GOOD - UserService.cs
public class UserService { }
// ❌ BAD - Multiple classes in one file
public class UserService { }
public class OrderService { } // Should be in OrderService.cs
Projects and Namespaces¶
Project Naming¶
Projects follow the pattern: ConnectSoft.{ProjectName}.{Layer}[.{Technology}]
| Pattern | Example | Description |
|---|---|---|
ConnectSoft.{ProjectName} |
Base project | Common code, constants, exceptions |
ConnectSoft.{ProjectName}.{Layer} |
EntityModel, DomainModel, ServiceModel |
Layer-specific projects |
ConnectSoft.{ProjectName}.{Layer}.{Technology} |
PersistenceModel.NHibernate, ServiceModel.RestApi |
Technology-specific implementations |
ConnectSoft.{ProjectName}.{Layer}.Impl |
DomainModel.Impl |
Implementation projects (separated from contracts) |
Namespace Naming¶
Namespaces match project structure exactly:
// Project: ConnectSoft.MicroserviceTemplate.EntityModel
namespace ConnectSoft.MicroserviceTemplate.EntityModel
{
public class MicroserviceAggregateRoot { }
}
Classes and Interfaces¶
Class Naming¶
- Use PascalCase
- Use descriptive nouns
- Avoid generic names like
Manager,Handler,Helper(be specific)
| Pattern | Example | Description |
|---|---|---|
| Entity | UserEntity, OrderEntity |
Domain entities |
| Repository | UserRepository, OrderRepository |
Data access repositories |
| Service | UserService, OrderProcessor |
Business logic services |
| Controller | UsersController, OrdersServiceController |
API controllers |
| Options | MicroserviceOptions, MongoDbOptions |
Configuration options |
| Extensions | ServiceCollectionExtensions, MongoDbExtensions |
Extension method containers |
| Constants | MicroserviceConstants, ServiceModelConstants |
Constant containers |
Interface Naming¶
- Prefix with
I - Use PascalCase
- Match implementation naming (without
Iprefix)
| Interface | Implementation | Pattern |
|---|---|---|
IUserRepository |
UserRepository |
Standard interface |
IMicroserviceAggregateRoot |
MicroserviceAggregateRootEntity |
Entity interface |
IMicroserviceAggregateRootsProcessor |
DefaultMicroserviceAggregateRootsProcessor |
Service interface |
IUnitOfWork |
NHibernateUnitOfWork, MongoDbUnitOfWork |
Abstract interface |
Read-Only Interface Pattern:
// Read-only interface
public interface IUserReadOnly { }
// Implementation
public class UserReadOnlyEntity : IUserReadOnly { }
Methods and Properties¶
Method Naming¶
- Use PascalCase
- Use verbs to describe actions
- Be specific about what the method does
| Pattern | Example | Description |
|---|---|---|
| Get | GetUserById, GetAllUsers |
Retrieval operations |
| Create | CreateUser, CreateOrder |
Creation operations |
| Update | UpdateUser, UpdateOrderStatus |
Update operations |
| Delete | DeleteUser, DeleteOrder |
Deletion operations |
| Process | ProcessPayment, ProcessOrder |
Business processing |
| Validate | ValidateUser, ValidateOrder |
Validation operations |
| Async Methods | GetUserByIdAsync, CreateUserAsync |
Async methods with Async suffix |
Avoid:
- ❌ Generic names: Get, Set, Update, Do
- ❌ Vague names: Handle, Process, Execute (without context)
Property Naming¶
- Use PascalCase
- Use nouns or noun phrases
- Boolean properties should be questions or statements:
IsActive,HasItems,CanDelete
| Pattern | Example | Description |
|---|---|---|
| Simple | UserName, Email, OrderDate |
Simple properties |
| Boolean | IsActive, HasPermission, CanEdit |
Boolean properties |
| Collection | Users, OrderItems, Permissions |
Collection properties |
| ID | UserId, OrderId, ObjectId |
Identifier properties (use Id, not ID) |
Variables and Parameters¶
Variable Naming¶
- Use camelCase
- Use descriptive names
- Avoid single letters (except in loops:
i,j,k)
| Pattern | Example | Description |
|---|---|---|
| Simple | userName, orderId, totalAmount |
Simple variables |
| Collection | users, orders, items |
Collection variables |
| Boolean | isActive, hasItems, canDelete |
Boolean variables |
| Async Result | result, response, entity |
Async method results |
Parameter Naming¶
Parameters follow the same rules as variables:
public async Task<User> GetUserById(Guid userId, CancellationToken cancellationToken = default)
{
// userId - camelCase parameter
// cancellationToken - camelCase parameter with default value
}
Private Fields¶
Field Naming¶
- Use camelCase with
this.prefix (preferred in ConnectSoft templates) - Or use
_prefix (alternative style)
// ✅ GOOD - camelCase with this. prefix (template style)
public class UserService
{
private readonly ILogger logger;
private readonly IUserRepository repository;
public UserService(ILogger logger, IUserRepository repository)
{
this.logger = logger;
this.repository = repository;
}
}
// ✅ ALTERNATIVE - _ prefix (also acceptable)
public class UserService
{
private readonly ILogger _logger;
private readonly IUserRepository _repository;
}
Constants¶
Constant Naming¶
- Use PascalCase (not UPPER_CASE)
- Group related constants in a static class
- Use descriptive names
// ✅ GOOD - PascalCase constants
public static class MicroserviceConstants
{
public const string NHibernateDIKey = "NHibernateDIKey";
public const string MongoDbDIKey = "MongoDbDIKey";
}
// ❌ BAD - UPPER_CASE (not used in ConnectSoft templates)
public const string MAX_CONNECTIONS = "100";
Constant Patterns¶
| Pattern | Example | Usage |
|---|---|---|
| Section Names | MicroserviceOptionsSectionName |
Configuration section names |
| DI Keys | NHibernateDIKey, MongoDbDIKey |
Dependency injection keys |
| Namespaces | BaseNamespace, MessagesNamespace |
Service model namespaces |
| Meter Names | MicroserviceTemplateMetricsMeterName |
Metrics meter names |
Enumerations¶
Enum Naming¶
- Use PascalCase
- Use singular names for the enum type
- Use PascalCase for enum values
Exceptions¶
Exception Naming¶
- Suffix with
Exception - Use descriptive names
- Indicate the problem
| Pattern | Example | Description |
|---|---|---|
| Not Found | UserNotFoundException, OrderNotFoundException |
Entity not found |
| Invalid | InvalidOperationException, InvalidConfigurationException |
Invalid state/configuration |
| Validation | ValidationException, OptionsValidationException |
Validation failures |
public class UserNotFoundException : Exception
{
public UserNotFoundException(Guid userId)
: base($"User with ID {userId} was not found.") { }
}
Service Model Naming¶
Request/Response DTOs¶
| Pattern | Example | Description |
|---|---|---|
| Request | CreateUserRequest, GetUserDetailsRequest |
Request DTOs |
| Response | CreateUserResponse, GetUserDetailsResponse |
Response DTOs |
| DTO | UserDto, OrderDto |
Data transfer objects |
// Service Model Request/Response
public class CreateMicroserviceAggregateRootRequest { }
public class CreateMicroserviceAggregateRootResponse { }
public class MicroserviceAggregateRootDto { }
Controller Naming¶
Controllers follow RESTful conventions:
| Pattern | Example | Route |
|---|---|---|
| Resource Controller | MicroserviceAggregateRootsServiceController |
api/MicroserviceAggregateRoots |
| Feature Controller | FeatureAController |
api/FeatureA |
[ApiController]
[Route("api/[controller]")]
public class MicroserviceAggregateRootsServiceController : ControllerBase
{
[HttpPost("MicroserviceAggregateRoots/")]
public async Task<CreateMicroserviceAggregateRootResponse> CreateMicroserviceAggregateRoot(...) { }
}
API Endpoint Naming¶
- Use nouns (resources), not verbs
- Use plural for collections
- Use RESTful conventions
| HTTP Method | Pattern | Example |
|---|---|---|
| GET | GET /api/{resource} |
GET /api/MicroserviceAggregateRoots |
| POST | POST /api/{resource} |
POST /api/MicroserviceAggregateRoots |
| PUT | PUT /api/{resource}/{id} |
PUT /api/MicroserviceAggregateRoots/{id} |
| DELETE | DELETE /api/{resource}/{id} |
DELETE /api/MicroserviceAggregateRoots/{id} |
Avoid:
- ❌ Verbs in URLs: /api/GetUser, /api/CreateOrder
- ❌ Singular resource names: /api/User (use /api/Users)
Domain Model Naming¶
Input/Output Models¶
| Pattern | Example | Description |
|---|---|---|
| Input | CreateUserInput, GetUserDetailsInput |
Domain input models |
| Output | CreateUserOutput, GetUserDetailsOutput |
Domain output models |
// Domain Model Input/Output
public class CreateMicroserviceAggregateRootInput { }
public class GetMicroserviceAggregateRootDetailsInput { }
public class CreateMicroserviceAggregateRootOutput { }
Processors and Retrievers¶
| Pattern | Example | Description |
|---|---|---|
| Processor Interface | IMicroserviceAggregateRootsProcessor |
Write operations interface |
| Processor Implementation | DefaultMicroserviceAggregateRootsProcessor |
Write operations implementation |
| Retriever Interface | IMicroserviceAggregateRootsRetriever |
Read operations interface |
| Retriever Implementation | DefaultMicroserviceAggregateRootsRetriever |
Read operations implementation |
Entity Model Naming¶
Entity Contracts and Implementations¶
| Pattern | Example | Description |
|---|---|---|
| Entity Interface | IMicroserviceAggregateRoot |
Entity contract |
| Entity Implementation | MicroserviceAggregateRootEntity |
Entity implementation |
| Read-Only Interface | IUserReadOnly |
Read-only entity contract |
| Read-Only Implementation | UserReadOnlyEntity |
Read-only entity implementation |
public interface IMicroserviceAggregateRoot : IGenericEntity<Guid>
{
Guid ObjectId { get; }
string? SomeValue { get; }
}
public class MicroserviceAggregateRootEntity : MicroserviceAggregateRoot, IMicroserviceAggregateRoot
{
public Guid ObjectId { get; set; }
public string? SomeValue { get; set; }
}
Messaging Model Naming¶
Commands and Events¶
| Pattern | Example | Description |
|---|---|---|
| Command | CreateOrderCommand, ProcessPaymentCommand |
Command messages |
| Event | OrderCreatedEvent, PaymentProcessedEvent |
Event messages (past tense) |
// Commands - Imperative verbs
public class CreateMicroserviceAggregateRootCommand : ICommand
{
public Guid ObjectId { get; set; }
}
// Events - Past tense
public class MicroserviceAggregateRootCreatedEvent : IEvent
{
public Guid ObjectId { get; set; }
public DateTimeOffset CreatedAt { get; set; }
}
Best Practices:
- ✅ Commands: Use imperative verbs (Create, Process, Approve)
- ✅ Events: Use past tense (Created, Processed, Approved)
- ❌ Avoid generic names: Message, Data, Info
Persistence Model Naming¶
Repositories¶
| Pattern | Example | Description |
|---|---|---|
| Repository Interface | IMicroserviceAggregateRootsRepository |
Repository contract |
| NHibernate Implementation | MicroserviceAggregateRootsRepository |
NHibernate repository |
| MongoDB Implementation | MicroserviceAggregateRootsMongoDbRepository |
MongoDB repository |
Specifications¶
| Pattern | Example | Description |
|---|---|---|
| Specification Interface | IMicroserviceAggregateRootsSpecification |
Specification contract |
| NHibernate Specification | MicroserviceAggregateRootsQueryableSpecification |
NHibernate queryable specification |
| MongoDB Specification | MicroserviceAggregateRootsMongoDbQueryableSpecification |
MongoDB queryable specification |
Actor Model Naming¶
Actor Interfaces and Implementations¶
| Pattern | Example | Description |
|---|---|---|
| Actor Interface | IBankAccountActor |
Actor contract |
| Actor Implementation | BankAccountActor |
Actor implementation |
| Actor Input | WithdrawInput, DepositInput |
Actor input models |
| Actor Output | WithdrawOutput, DepositOutput |
Actor output models |
public interface IBankAccountActor : IGrainWithGuidKey
{
Task<WithdrawOutput> Withdraw(WithdrawInput input);
}
public class BankAccountActor : Grain, IBankAccountActor
{
public Task<WithdrawOutput> Withdraw(WithdrawInput input) { }
}
Database Naming¶
Tables and Collections¶
| Database | Pattern | Example | Description |
|---|---|---|---|
| SQL Tables | PascalCase, plural | Users, Orders, MicroserviceAggregateRoots |
SQL table names |
| MongoDB Collections | PascalCase, plural | Users, Orders, MicroserviceAggregateRoots |
MongoDB collection names |
| Schemas | Namespace-style | ConnectSoft.MicroserviceTemplate |
SQL schema names |
Columns and Fields¶
| Pattern | Example | Description |
|---|---|---|
| SQL Columns | PascalCase | ObjectId, SomeValue, CreatedOn |
| MongoDB Fields | PascalCase | ObjectId, SomeValue, CreatedOn |
Indexes¶
| Pattern | Example | Description |
|---|---|---|
| SQL Indexes | IX_{Table}_{Column} |
IX_Users_Email, IX_Orders_CustomerId |
| Composite Indexes | IX_{Table}_{Column1}_{Column2} |
IX_Orders_Status_CreatedOn |
Configuration and Options¶
Options Classes¶
| Pattern | Example | Description |
|---|---|---|
| Options Class | MicroserviceOptions, MongoDbOptions |
Configuration options |
| Section Name Constant | MicroserviceOptionsSectionName |
Configuration section name |
| Validator | ValidateMicroserviceOptions |
Options validator |
public sealed class MicroserviceOptions
{
public const string MicroserviceOptionsSectionName = "Microservice";
[Required]
required public string MicroserviceName { get; set; }
}
Extension Methods¶
Extension Method Naming¶
Extension method classes follow the pattern: {TargetType}Extensions
| Pattern | Example | Description |
|---|---|---|
| Service Collection | ServiceCollectionExtensions, MongoDbExtensions |
DI registration extensions |
| Application Builder | ApplicationBuilderExtensions |
Middleware pipeline extensions |
| Endpoint Route Builder | EndpointRouteBuilderExtensions |
Endpoint mapping extensions |
Naming Pattern: Add{Feature}, Use{Feature}, Map{Feature}
File and Folder Naming¶
Files¶
- Match class name:
UserService.cscontainsUserServiceclass - Use PascalCase:
OrderRepository.cs,MicroserviceOptions.cs - One class per file: Each file contains one primary class/interface
Folders¶
Folders follow namespace structure and use PascalCase:
| Folder | Purpose | Example |
|---|---|---|
| Controllers | API controllers | Controllers/, RestApi/ |
| Repositories | Repository implementations | Repositories/ |
| Mappings | Entity mappings | Mappings/, NHibernate/, MongoDb/ |
| Options | Configuration options | Root of Options project |
| Extensions | Extension methods | Root of ApplicationModel project |
Metrics Naming¶
Metric Names¶
Metrics use lowercase with dots (OpenTelemetry convention):
| Pattern | Example | Description |
|---|---|---|
| Meter Name | connectsoft.microservicetemplate |
Meter name |
| Counter | connectsoft.microservicetemplate.aggregateroot.added |
Counter metric |
| Duration | connectsoft.microservicetemplate.aggregateroot.add.duration |
Duration metric |
Use Cases and Operations Naming¶
Best Practices¶
- Use verbs to describe actions
- Avoid generic names like
Get,Set,Update
Examples¶
E-commerce Domain:
- AddItemToCart
- PlaceOrder
- CancelOrder
User Management Domain:
- RegisterUser
- ChangeUserPassword
- DeactivateUserAccount
Financial Domain:
- InitiateTransfer
- ProcessRefund
- ReconcileAccount
Naming Conventions Best Practices¶
Do's¶
- ✅ Use PascalCase for classes, methods, properties, constants
- ✅ Use camelCase for variables and parameters
- ✅ Be descriptive - names should clearly indicate purpose
- ✅ Follow established patterns - use template conventions consistently
- ✅ Match file names to class names - one class per file
- ✅ Use verbs for methods -
CreateUser,GetOrderDetails - ✅ Use nouns for classes -
UserService,OrderRepository - ✅ Prefix interfaces with
I-IUserRepository,IOrderService - ✅ Suffix exceptions with
Exception-UserNotFoundException - ✅ Use
Asyncsuffix for async methods -GetUserAsync
Don'ts¶
- ❌ Don't use abbreviations unless widely accepted (
Id,Http) - ❌ Don't use generic names -
Manager,Handler,Helper - ❌ Don't use Hungarian notation -
strUserName,intCount - ❌ Don't use UPPER_CASE for constants (use PascalCase)
- ❌ Don't mix naming styles - be consistent within a project
- ❌ Don't use verbs in URLs -
/api/GetUser❌ →/api/Users✅ - ❌ Don't use singular for resource collections -
/api/User❌ →/api/Users✅ - ❌ Don't skip
Asyncsuffix for async methods - ❌ Don't use single letters (except in loops)
- ❌ Don't use magic strings - use constants instead
For additional naming rules, refer to StyleCopAnalyzers naming rules.
Code Style¶
StyleCopAnalyzers enforces a wide range of code style rules. Key categories include:
- Layout Rules: Spacing, indentation, and code organization
- Readability Rules: Code clarity and maintainability
- Maintainability Rules: Code structure and complexity
- Ordering Rules: Member ordering within classes
For complete details, see the StyleCopAnalyzers documentation.
Documentation¶
XML documentation comments are required for public APIs and should follow standard conventions:
- Use proper XML documentation tags (
<summary>,<param>,<returns>,<exception>, etc.) - Provide meaningful descriptions for all public members
- Include parameter descriptions
- Document return values and exceptions
Refer to DocumentationAnalyzers for comprehensive documentation guidelines and rules.
ASP.NET Core Best Practices¶
When developing ASP.NET Core applications, follow best practices identified by AspNetCoreAnalyzers:
- Proper use of dependency injection
- Correct middleware ordering
- Appropriate use of async/await patterns
- Security best practices
- Performance optimization guidelines
See AspNetCoreAnalyzers for detailed ASP.NET Core-specific rules and recommendations.
Additional Guidelines¶
Code Organization¶
- Follow the project's solution structure and naming conventions
- Group related functionality together
- Maintain clear separation of concerns
Error Handling¶
- Use appropriate exception types
- Provide meaningful error messages
- Log errors appropriately
Performance¶
- Avoid premature optimization
- Use async/await for I/O-bound operations
- Consider memory allocation patterns
Integration with IDEs¶
These analyzers integrate seamlessly with Visual Studio and other IDEs, providing: - Real-time code analysis - Automatic code fixes where available - IntelliSense integration - Build-time warnings and errors
Ensure that the appropriate analyzer NuGet packages are installed in your projects to benefit from these rules during development.
Configuration¶
Analyzer rules can be configured using:
- Rule set files (.ruleset) in Visual Studio
- EditorConfig files (.editorconfig) for cross-IDE compatibility
- stylecop.json files for StyleCop-specific settings
Refer to each analyzer's documentation for configuration options and customization.