dotnet-guidelines
Skill from roeibajayo/claude-tools
- Category: discovered
- Tags: github, community
- Version: 1.0.0
- Author: walid
- Downloads: 0
- Updated: 2025-11-22
Download the latest version (v1.0.0) from this page.
SKILL.md
---
name: dotnet-guidelines
description:
dotnet coding guidelines and best practices. MUST follow these rules.
Use when reviewing or writing .NET code or tasks.
---
# IMPORTANT Server Guidelines
- ALWAYS Use Primary Constructors for classes.
- ALWAYS Prefer `record` types for immutable data structures.
- NEVER mix multiple classes or DTOs in a single file, even if they are small. Filename ALWAYS matches the class or DTO name, for example `UserDto.cs` for a `UserDto` class.
- Private fields should NOT be prefixed with `_` (e.g., `repository` not `_repository`).
- Add (.) to the end of all server-side log messages.
- Use `string?` over `string` for nullable strings.
- Use `var` for local variables when type is obvious.
- Don't use Regions in code files.
- Use Collection initializers for collections: instead of `new List<string>()`, use `new() { "item1", "item2" }`, and instead of `list.ToArray()` use `[.. list]`.
- Use Anonymous function static: instead of `list.Select(x => new Dto(x.SameProperty))`, use `list.Select(static x => new Dto(x.SameProperty))`.
- ALWAYS use `sealed` accessor for classes or records if not intended for inheritance.
- ALWAYS use `internal` accessor for internal classes or records.
- NEVER inject or create `HttpClient` and `IHttpClientFactory`, instead use the `IRestClient` interface.
- NEVER register services directly in `IServiceCollection`. Instead, use the `ITransientService`, `IScopedService`, or `ISingletonService` interfaces to register services with the appropriate lifetimes.
- ALWAYS use `ILogger` with Structured logging to log, no string interpolation and no other logging methods.
- ALWAYS use cancellation tokens for asynchronous methods.
- ALWAYS use `IMemoryCore` for time-based in-memory caching, NEVER use `IMemoryCache`.
- ALWAYS use Data Transfer Objects (DTO) for API communication, validated with attributes.
- ALWAYS use `x` as a parameter name in lambdas and anonymous functions.
- If any backend changes are made, run `dotnet build` in the root and ensure no build errors for the entire solution.
## Code Organization Principles
### Avoid Unnecessary Wrapper Methods
**Rule**: Do NOT create wrapper methods for specific cases that simply call another method with fixed parameters. Call the base method directly instead.
**Example - DON'T**:
```csharp
// ❌ Don't create this wrapper method for a single use case:
public async Task<int> CreateAgentHistoryClearedMessageAsync(int sessionId)
{
var request = new CreateMessageRequest(
Type: MessageType.System,
Content: "Agent history has been cleared",
Status: MessageStatus.Done
);
return await CreateMessageAsync(sessionId, request);
}
```
**Example - DO**:
```csharp
// ✅ Instead, call CreateMessageAsync directly where needed:
await messageService.CreateMessageAsync(
sessionId,
new CreateMessageRequest(
MessageType.System,
"Agent history has been cleared",
MessageStatus.Done
)
);
```
**When to create a helper method**:
- When there's complex logic beyond just parameter mapping
- When the same combination is used in multiple places (3+ times)
- When the method provides meaningful abstraction or validation