.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.
Use Source Link for libraries shared via NuGet
- Include the correct Source Link package in your library
- Verify the quality of the NuGet package generated by the library using NuGet Package Explorer
- Publish the symbols with the library NuGet package
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
- Generate an .editorconfig in Visual Studio to enforce your current code conventions
- Adopt an .editorconfig from a popular open source project to align with its conventions
- Explore the Code style and quality analysis options and author a new file from scratch
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
- Use the powerful XML doc comment syntax to annotate types, methods, and properties
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
}