Skip to content
Xperience by Kentico StyleguideXperience by Kentico StyleguideXperience by Kentico Styleguide
GitHubYouTube

.NET and C#

.NET

Use global solution configuration files

Recommended

  • In the root of your repository, create a Directory.Build.props file for shared project configuration
  • In the root of your repository, create a Directory.Packages.props file for shared project package version definition
  • In the root of your repository, create a Directory.Build.targets file for shared project build actions

Why?

Directory.Build.props and Directory.Build.targets are a convenient way to define common MSBuild properties and behavior in a single location. While these files are most useful in libraries that are shared via NuGet packages, applications can also benefit from them.

Adding the following to a Directory.Build.props would enable nullable reference types for the entire solution and ensure any nullability warnings are treated as compilation errors:

Why?

If you embed ownership metadata in your compiled assemblies, having to repeat this metadata in every .csproj file can be tedious and error prone. Instead it can be specified in Directory.Build.props and applied to all projects:

Why?

It’s very uncommon to need different versions of packages across all projects in a modern .NET solution. However, maintaining package version numbers in multiple .csproj files can result in inconsistent versions.

Adopting Central Package Management and the Directory.Packages.props file can simply NuGet package management.

Use the latest supported Target Framework for applications

Recommended

  • Target .NET 6.0 for all projects in the solution (latest supported version as of 2023/10) and adopt newer versions as they become supported. See Compatibility and requirements.

Why?

Xperience by Kentico requires ASP.NET Core 6.0 and .NET Standard 2.0 is basically obsolete for modern .NET applications and libraries that don’t need to support .NET Framework (e.g. .NET 4.x).

Why?

Xperience by Kentico’s product model includes regular refreshes to the platform. To get the latest features, developers will need to regularly apply refreshes and update their custom code to turn on these features. These regular updates are a great opportunity to ensure the latest supported version of .NET is being used.

Why?

Microsoft is releasing new version of C# along with new versions of .NET on a yearly cadence. To benefit from the newest language features (ex: C#10), developers need to be on the latest version of .NET.

Why?

Source Link is a technology for .NET that enables developers to debug into the source of Release compiled assemblies packaged in NuGet packages.

Visual Studio has been investing in the developer experience of Source Link by exposing the source code of NuGet packages built with Source Link directly in the Visual Studio Solution Explorer.

Being able to debug the source code of a NuGet when running an application helps developers better understand how to use a package and diagnose issues more quickly.

Why?

Source Link can be used for internal packages exposed through a private NuGet feed (like GitLab or Azure DevOps) or through a public NuGet server like NuGet.org, so all teams and projects can benefit.

C#

Enable Nullable Reference Types

Recommended

  • Turn on compiler analysis for nullable reference types for any project supporting C# 8 or above
  • Add <nullable>enable</nullable> to a <PropertyGroup> in your .csproj file to enable nullable reference types
  • Add <WarningsAsErrors>nullable</WarningsAsErrors> to a <PropertyGroup> in your .csproj file to treat nullable reference type warnings as compilation errors

Why?

One of the most common exceptions developers encounter in their code is the NullReferenceException. This typically happens because of C#‘s implicit type union of all reference types and the value null. The compiler can’t tell the developer that a value might be null before it is used, so developers are forced to add checks themselves. It’s easy to forget these checks which leads to the exceptions are runtime.

Enabling nullable reference types makes the type union of reference types and null explicit, which means the compiler can alert us when we haven’t guarded against null values.

Why?

Nullable reference types were a C# language feature enhancement to help developers catch errors at compile time. By default, the compiler will treat missing null checks or nullable type mismatches as warnings, but those defeat the purpose of using the compiler to help us write more robust code. By having the compiler emit errors instead of warnings, we ensure we are getting the most protection for our application with this feature.

Use EditorConfig for Consistent C#

Suggested

Why?

.NET has been moving in the direction of providing tools and configuration for enabling and enforcing conventions within projects. The dotnet format command provided by the .NET CLI works with .editorconfig files to automatically clean up a project’s source code to meet the code style and quality to match the configuration.

Using the Code Cleanup on Save extension (or built-in Visual Studio features) ensures the IDE handles formatting your files according to .editorconfig rules any time you make a change.

Why?

Defining formatting conventions at the beginning of a project and providing tooling to automatically apply this formatting reduces noise in source control diffs/merges, reduces the cognitive overhead for developers new to a project, and helps prevent team debates over formatting in the future.

Add XML Doc Comments

Recommended

Why?

Swagger API documentation for HTTP/REST APIs has become a standard in most enterprise web applications. XML doc comments helps to make these auto-generated pages more useful with human readable descriptions.

Why?

A type name can give a developer a hint as to what a type is (ex: IPageRetriever), but the name alone might not indicate when or why a type or method should be used. XML doc comments are a great place to add these explanations. Comments that clearly describe what something is and why it exists, while avoiding describing how it works, can help developers using those types and methods from needing to explore the source code.

Why?

Method overloading is a useful C# feature, but variations on parameter lists can be difficult to understand without XML doc comments detailing what parameters are used for.

Why?

Proper use of XML doc comments can be refactor-proof when referring to other code as symbols instead of strings (ex <see cref="SomeType" />).

/// <summary>
/// Validates URls based on the configuration
/// supplied by <see cref="URLConfiguration" />
/// </summary>
public class URLValidator
{
    private readonly URLConfiguration config;

    public URLValidator(IOptions<URLConfiguration> config) =>
      this.config = config.Value;

    // more methods
}