Consistent formatting in a codebase is a good thing. We can achieve this in dotnet using
dotnet format, used in combination with the npm packages
lint-staged. This post shows how.
This has been updated to work with the latest versions of
Updated linting 07/04/2022
If you're interested in formatting, you might be interested in linting; formatting's big sister. C# has linting too; read about it here.
Consistent formatting makes code less confusing to newcomers and it allows whoever is working on the codebase to reliably focus on the task at hand. Not "fixing curly braces because Janice messed them up with her last commit". (A
git commit message that would be tragic in so many ways.)
Please note that this plugin is under active development, and might not be ready to run on production code yet. It will break your code.
Not a ringing endorsement.
dotnet-format: a new hope
is a code formatter for dotnet that applies style preferences to a project or solution. Preferences will be read from an
.editorconfigfile, if present, otherwise a default set of preferences will be used.
It can be installed with:
dotnet tool install -g dotnet-format
The VS Code C# extension will make use of this formatter, we just need to set the following in our
Customising our formatting
If we'd like to deviate from the default formatting options then create ourselves an
.editorconfig file in the root of our project. Let's say we prefer more of the K & R style approach to braces instead of the C# default of Allman style. To make
dotnet-format use that we'd set the following:
# Remove the line below if you want to inherit .editorconfig settings from higher directories
root = true
# See https://github.com/dotnet/format/blob/master/docs/Supported-.editorconfig-options/index.md for reference
csharp_new_line_before_open_brace = none
csharp_new_line_before_catch = false
csharp_new_line_before_else = false
csharp_new_line_before_finally = false
csharp_new_line_before_members_in_anonymous_types = false
csharp_new_line_before_members_in_object_initializers = false
csharp_new_line_between_query_expression_clauses = true
With this in place it's K & R all the way baby!
Run linters against staged git files and don't let 💩 slip into our code base!
To add this to our (otherwise C# codebase), we're going to need a
npm init --yes
npx husky-init && npm install
npm install lint-staged --save-dev
We should have a new file living at
.husky/pre-commit which is our pre-commit hook.
Within that file we should replace
npm test with
npx lint-staged --relative. This is the command that will be run on commit.
lint-staged will be run and we're specifying
relative so that relative file paths will be used. This is important as
--include accepts "a list of relative file or folder paths to include in formatting". Absolute paths (the default) won't work - and if we pass them to
dotnet format, it will not format the files.
Finally we add the following entry to the
"*.cs": "dotnet format --include"
This is the task that will be invoked by
lint-staged against files with a
.cs suffix on commit. When
lint-staged runs, it will pass a list of relative file paths to
dotnet format. So if we'd staged two files it might end up executing a command like this:
dotnet format --include src/server-app/Server/Controllers/UserController.cs src/server-app/Server/Controllers/WeatherForecastController.cs
We should end up with a
package.json that looks something like this:
"description": "[![Shared Build Status](https://dev.azure.com/investec/maas/_apis/build/status/shared?repoName=maas)](https://dev.azure.com/investec/maas/_build/latest?definitionId=1128&repoName=maas)",
"test": "echo \"Error: no test specified\" && exit 1",
"prepare": "husky install"
"*.cs": "dotnet format --include"
By and large we don't have to think about this; the important take home is that we're now enforcing standardised formatting for all C# files upon commit. Everything that goes into the codebase will be formatted in a consistent fashion.
CSharpier - update 16/05/2021
There is an alternative to the CSharp Prettier project. It's being worked on by Bela VanderVoort and it goes by the name of csharpier. When comparing CSharpier and dotnet-format, Bela put it like this:
I could see CSharpier being the non-configurable super opinionated formatter and dotnet-format being for the people that do want to have options.
Check it out!