# C# Framework Standards · CS-04

## Standard Metadata

- Area: C#
- Owner: Backend Steering group
- Last reviewed: 2026-09-09
- Next review due from: 2026-12-01
- Enforcement: CodeAnalysis / Rosyln Analyser / code review
- Status: Active

## Use C# type aliases instead of the types from the `System` namespace · CS-04.1 · **MUST**

For instance, use `object` instead of `Object`, `string` instead of `String`, and `int` instead of `Int32`. These aliases have been introduced to make the primitive types a first class citizen of the C# language so use them accordingly.

**Roslyn Analyzer Rule [SA1121](https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1121.md)**

---

## Properly name properties, variables or fields referring to localised resources · CS-04.2 · **SHOULD**

The guidelines in this topic apply to localisable resources such as error messages and menu text.

* Use Pascal casing in resource keys.
* Provide descriptive rather than short identifiers. Keep them concise where possible, but don't sacrifice readability.
* Use only alphanumeric characters in naming resources.

---

## Don't hardcode strings that change based on the deployment · CS-04.3 · **MUST**

Examples include connection strings, server addresses, etc.

In ASP.NET Core, use `IConfiguration` from the `Microsoft.Extensions.Configuration` packages to access data in code, and store the actual values in `appsettings.json` files, user secrets, environment variables, Azure Configuration, Azure Key Vault, etc.

In ASP.NET, use the `ConfigurationManager` class and its `AppSettings` and `ConnectionStrings` properties. Maintain the actual values in `app.config` or `web.config` files.

---

## Build with the highest warning level · CS-04.4 · **MUST**

Configure the development environment to use **Warning Level 4** for the C# compiler, and enable the option **Treat warnings as errors**. This allows the compiler to enforce the highest possible code quality.

**Roslyn Analyzer Rule [AV2210](https://github.com/bkoelman/CSharpGuidelinesAnalyzer/blob/master/docs/Overview.md#av2210-build-with-the-highest-warning-level-)**

---

## Only use the `dynamic` keyword when talking to a dynamic object · CS-04.5 · **MUST**

The `dynamic` keyword has been introduced for working with dynamic languages. Using it introduces a serious performance bottleneck because the compiler has to generate some complex Reflection code.
 
Use it only for calling methods or members of a dynamically created instance (using the `Activator`) class as an alternative to `Type.GetProperty()` and `Type.GetMethod()`, or for working with COM Interop types.

**Roslyn Analyzer Rule [AV2230](https://github.com/bkoelman/CSharpGuidelinesAnalyzer/blob/master/docs/Overview.md#av2230-only-use-the-dynamic-keyword-when-talking-to-a-dynamic-object-)**

---

## Favour `async`/`await` over the Task · CS-04.6 · **MUST**

Using the new C# 5.0 keywords results in code that can still be read sequentially and also improves maintainability a lot, even if you need to chain multiple asynchronous operations. For example, rather than defining your method like this:

```csharp
public Task<Data> GetDataAsync()
{
    return MyWebService.FetchDataAsync()
                       .ContinueWith(t => new Data (t.Result));
}
```

Define it like this:

```csharp
public async Task<Data> GetDataAsync()
{
    var result = await MyWebService.FetchDataAsync();

    return new Data (result);
}
```

**Roslyn Analyzer Rule [AV2235](https://github.com/bkoelman/CSharpGuidelinesAnalyzer/blob/master/docs/Overview.md#av2235-favor-asyncawait-over-task-continuations-)**
