Naming Conventions in ConnectSoft Microservice Template
Purpose & Overview
Naming Conventions establish consistent standards for naming classes, methods, properties, namespaces, projects, and other code elements throughout the ConnectSoft Microservice Template. Consistent naming conventions improve code readability, maintainability, and team collaboration by ensuring that developers can quickly understand the purpose and structure of code elements.
The naming conventions in this template follow Microsoft .NET Framework Design Guidelines while incorporating domain-driven design and Clean Architecture principles to create a cohesive, predictable naming strategy across all layers of the microservice.
Naming Philosophy
"There are only two hard things in Computer Science: cache invalidation and naming things."
— Phil Karlton
Good naming is critical for code maintainability. The ConnectSoft Microservice Template follows established .NET conventions while adding domain-specific patterns that make the codebase self-documenting and easy to navigate.
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 in this template |
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.MicroserviceTemplate.{Layer}[.{Technology}]
| Pattern |
Example |
Description |
ConnectSoft.MicroserviceTemplate |
Base project |
Common code, constants, exceptions |
ConnectSoft.MicroserviceTemplate.{Layer} |
EntityModel, DomainModel, ServiceModel |
Layer-specific projects |
ConnectSoft.MicroserviceTemplate.{Layer}.{Technology} |
PersistenceModel.NHibernate, ServiceModel.RestApi |
Technology-specific implementations |
ConnectSoft.MicroserviceTemplate.{Layer}.Impl |
DomainModel.Impl |
Implementation projects (separated from contracts) |
Examples:
- ConnectSoft.MicroserviceTemplate.EntityModel - Entity contracts
- ConnectSoft.MicroserviceTemplate.DomainModel - Domain contracts
- ConnectSoft.MicroserviceTemplate.DomainModel.Impl - Domain implementations
- ConnectSoft.MicroserviceTemplate.ServiceModel.RestApi - REST API controllers
- ConnectSoft.MicroserviceTemplate.PersistenceModel.NHibernate - NHibernate persistence
Namespace Naming
Namespaces match project structure exactly:
// Project: ConnectSoft.MicroserviceTemplate.EntityModel
namespace ConnectSoft.MicroserviceTemplate.EntityModel
{
public class MicroserviceAggregateRoot { }
}
// Project: ConnectSoft.MicroserviceTemplate.ServiceModel.RestApi
namespace ConnectSoft.MicroserviceTemplate.ServiceModel.RestApi
{
public class MicroserviceAggregateRootsServiceController { }
}
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
I prefix)
| 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) |
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";
}
// ✅ GOOD - Section name constants
public sealed class MicroserviceOptions
{
public const string MicroserviceOptionsSectionName = "Microservice";
}
// ❌ BAD - UPPER_CASE (not used in this template)
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 |
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
| 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 |
public interface IMicroserviceAggregateRootsProcessor
{
Task<IMicroserviceAggregateRoot> CreateMicroserviceAggregateRoot(
CreateMicroserviceAggregateRootInput input,
CancellationToken token = default);
}
public class DefaultMicroserviceAggregateRootsProcessor : IMicroserviceAggregateRootsProcessor
{
// 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 |
| Keyed Repository |
MicroserviceAggregateRootsMongoDbKeyedRepository |
Keyed DI repository |
public interface IMicroserviceAggregateRootsRepository { }
// NHibernate
public class MicroserviceAggregateRootsRepository : GenericRepository<...>, IMicroserviceAggregateRootsRepository { }
// MongoDB
public class MicroserviceAggregateRootsMongoDbRepository : MongoDbRepository<...>, IMicroserviceAggregateRootsRepository { }
Specifications
| Pattern |
Example |
Description |
| Specification Interface |
IMicroserviceAggregateRootsSpecification |
Specification contract |
| NHibernate Specification |
MicroserviceAggregateRootsQueryableSpecification |
NHibernate queryable specification |
| MongoDB Specification |
MicroserviceAggregateRootsMongoDbQueryableSpecification |
MongoDB queryable specification |
public interface IMicroserviceAggregateRootsSpecification { }
public class MicroserviceAggregateRootsQueryableSpecification : QueryableSpecification<...>, IMicroserviceAggregateRootsSpecification { }
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) { }
}
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; }
[Required]
[Range(0, int.MaxValue)]
required public int StartupWarmupSeconds { get; set; } = 20;
}
[OptionsValidator]
public partial class ValidateMicroserviceOptions : IValidateOptions<MicroserviceOptions>
{
}
Configuration Section Naming
Configuration sections use PascalCase and match the options class name:
{
"Microservice": {
"MicroserviceName": "MyService",
"StartupWarmupSeconds": 20
},
"PersistenceModel": {
"MongoDb": {
"MongoDbConnectionStringKey": "MongoDb",
"DatabaseName": "MyDatabase"
}
}
}
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 |
internal static class MongoDbExtensions
{
internal static IServiceCollection AddMongoDbPersistence(
this IServiceCollection services,
IConfiguration configuration)
{
// Implementation
}
}
Naming Pattern: Add{Feature}, Use{Feature}, Map{Feature}
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 |
File and Folder Naming
Files
- Match class name:
UserService.cs contains UserService class
- 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 |
public static class MicroserviceTemplateMetrics
{
public const string MicroserviceTemplateMetricsMeterName = "connectsoft.microservicetemplate";
public const string AggregateRootsAddedCounterName = "connectsoft.microservicetemplate.aggregateroot.added";
public const string AggregateRootsAddDurationName = "connectsoft.microservicetemplate.aggregateroot.add.duration";
}
Exception Naming
Exception Classes
- 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.") { }
}
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 this template)
- 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 and Static Values
Constant Patterns
| Pattern |
Example |
Usage |
| Section Names |
MicroserviceOptionsSectionName = "Microservice" |
Configuration sections |
| DI Keys |
NHibernateDIKey = "NHibernateDIKey" |
Dependency injection keys |
| Namespaces |
BaseNamespace = "ConnectSoft.MicroserviceTemplate.servicemodel/1975/" |
Service model namespaces |
| Meter Names |
MicroserviceTemplateMetricsMeterName = "connectsoft.microservicetemplate" |
Metrics meter names |
| Store Names |
BankAccountActorsStoreName = "bankAccountActorsStore" |
Actor store names |
Enumerations
Enum Naming
- Use PascalCase
- Use singular names for the enum type
- Use PascalCase for enum values
public enum OrderStatus
{
Pending,
Processing,
Completed,
Cancelled
}
public enum McpServerTransportType
{
Stdio = 1,
Http = 2
}
Best Practices Summary
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
Async suffix 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
Async suffix for async methods
- ❌ Don't use single letters (except in loops)
- ❌ Don't use magic strings - use constants instead
Examples from Template
Complete Example: REST API Controller
namespace ConnectSoft.MicroserviceTemplate.ServiceModel.RestApi
{
[ApiController]
[Route("api/[controller]")]
public class MicroserviceAggregateRootsServiceController : ControllerBase
{
private readonly ILogger<MicroserviceAggregateRootsServiceController> logger;
private readonly IMicroserviceAggregateRootsRetriever retriever;
private readonly IMicroserviceAggregateRootsProcessor processor;
private readonly IMapper mapper;
public MicroserviceAggregateRootsServiceController(
ILogger<MicroserviceAggregateRootsServiceController> logger,
IMicroserviceAggregateRootsRetriever retriever,
IMicroserviceAggregateRootsProcessor processor,
IMapper mapper)
{
this.logger = logger;
this.retriever = retriever;
this.processor = processor;
this.mapper = mapper;
}
[HttpPost("MicroserviceAggregateRoots/")]
public async Task<CreateMicroserviceAggregateRootResponse> CreateMicroserviceAggregateRoot(
[FromBody] CreateMicroserviceAggregateRootRequest request,
CancellationToken token = default)
{
// Implementation
}
}
}
Complete Example: Domain Processor
namespace ConnectSoft.MicroserviceTemplate.DomainModel.Impl
{
public class DefaultMicroserviceAggregateRootsProcessor : IMicroserviceAggregateRootsProcessor
{
private readonly IUnitOfWork unitOfWork;
private readonly IMicroserviceAggregateRootsRepository repository;
private readonly IEventBus eventBus;
private readonly ILogger logger;
public DefaultMicroserviceAggregateRootsProcessor(
IUnitOfWork unitOfWork,
IMicroserviceAggregateRootsRepository repository,
IEventBus eventBus,
ILogger<DefaultMicroserviceAggregateRootsProcessor> logger)
{
this.unitOfWork = unitOfWork;
this.repository = repository;
this.eventBus = eventBus;
this.logger = logger;
}
public async Task<IMicroserviceAggregateRoot> CreateMicroserviceAggregateRoot(
CreateMicroserviceAggregateRootInput input,
CancellationToken token = default)
{
// Implementation
}
}
}
References
Summary
The ConnectSoft Microservice Template naming conventions provide:
- ✅ Consistency: Predictable naming patterns across all layers
- ✅ Clarity: Self-documenting code through descriptive names
- ✅ Maintainability: Easy to navigate and understand codebase
- ✅ Standards Compliance: Follows Microsoft .NET guidelines
- ✅ Domain-Driven: Aligns with DDD and Clean Architecture principles
By following these conventions, teams can:
- Onboard Quickly: New developers understand code structure immediately
- Maintain Easily: Consistent patterns make refactoring and updates straightforward
- Collaborate Effectively: Shared understanding of naming reduces confusion
- Scale Confidently: Established conventions support growth
Naming conventions are the foundation of code quality—they enable teams to write code that is not just functional, but also readable, maintainable, and professional.