Getting started with the Roslyn Analyzers for dotnet

Published on Saturday, November 19, 2022

My desk is a mess. There's papers, stickers, spare parts, glasses cleaning cloths, at least one coffee cup, tiny plush toys, and lots of knick knacks and other crap. It is my mess and I know where everything is so it's not a problem... until my wife needs to get something off the desk.

Luckily it's a rare thing that she needs to get something off my desk, and I can usually guide her to whatever she's after. So what all of this have to do with coding and Roslyn Analyzers? Unlike my desk, which is almost only accessed by me, the code I write is almost always read by others. It starts with a code review, but will continue for years as others maintain and add features to the code. So, unlike my mess on the desk, messy code is the entire teams problem.

Identify messy code

Messy code is any code that doesn't follow your coding style. However, without tooling to help, a coding style is just another document that very few will read. Luckily in .NET (or dotnet if you are in the #dropthedot crowd...) there are tools built right into the compiler, the .NET Compiler Platform (Roslyn) Analyzers, or Roslyn Analyzers for short.

If you haven't specified your own coding style, a good starting point is to use the official coding conventions provided by Microsoft

You can also look at the Framework Design Guidelines on how to design libraries to look, feel and behave in a dotnet:y way.

What can the Roslyn Analyzers help us with?

The Roslyn Analyzers analyze two aspects of your code, Code Style and Code Quality.

Code Style rules

Code Style rules help with maintaining a coding style throughout code and are grouped into 5 categories and are named IDExxxx.

  • Language Defines how the code is written using the language features, such as using parenthesis for clarification or prepending local calls with this..

  • Unnecessary code Detects code that can be simplified or code that is not in use. Since this is a compile time analysis, code called using reflection and magic strings are likely not detected.

  • Miscellaneous This contains some rules around wrong or old usage of SuppressMessageAttribute.

  • Formatting Contains one rule IDE0055, which is all the things formatting. It validates configuration around new lines, indentation, spacing and how using directives are sorted.

  • Naming Contains one rule IDE1006 with a very customizable configuration for how fields, properties, classes etc are named. Should local fields be prepended with _, should methods use cameCase or PascalCase and lots more.

Code Quality Rules

Code Quality rules are there to help writing better and safer code by warning when the code isn't using the .NET APIs as expected, or when the code references unsafe methods and more. These rules are grouped into 11 categories and are mostly named CAxxxx.

  • Design Helps with following the .NET Framework Design Guidelines with rules to ensure the code validates arguments in public methods, enums have zero values, classes are declared in a namespace and lots more.

  • Documentation In .NET 7 there's only one rule CA1200 which validates that cref in XML-documentation doesn't include prefixes.

  • Globalization Helps with code that is affected by the current culture or that is used to localize the application.

  • Portability and interoperability Validates rules when interacting with COM clients.

  • Maintainability Rules to help write more maintainable code, such as not using large dependency trees and using nameof() instead of magic strings.

  • Naming Warns if names violating the .NET naming guidelines for example enums with Flag attribute should be pluralized and identifiers should not differ only by case.

  • Performance Contains a bunch of rules to help writing more performant code, for instance using Length or Count properties instead of Linq's Count() method.

  • SingleFile These rules have the name IL3000 to IL3003 and help with issues related to publishing as single file, like avoid the property Assembly.Location since it returnsstring.Empty when publishing as single file.

  • Reliability Helps with writing code that use threads and memory correctly, for example disposing objects that implement IDisposable.

  • Security Provide assistance to discover SQL Injection, using unsafe encryption algorithms, using antiforgery tokens in ASP.NET Core MVC Controllers, and lots more.

  • Usage These rules helps with writing code that could cause unexpected behavior or that are likely to cause issues. For example warn when calling virtual methods inside a constructor, or passing a URI as a string when there is a overload that accepts Uri.

How to enable the Roslyn Analyzers

So how do we enable the Roslyn Analyzers? Short answer, if you are targeting net5.0 or above they are already enabled, but only a small set of rules. If you are targeting a version earlier than net5.0, for instance net472, the analyzers can be enabled in the project file, as long as you are using a SDK-style project file.

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>net472</TargetFramework>
    <EnableNETAnalyzers>true</EnableNETAnalyzers>
  </PropertyGroup>

</Project>

If you're not using an SDK-style project file, you can use a NuGet package Microsoft.CodeAnalysis.NetAnalyzers.

Configure the Roslyn Analyzers

In .NET 7 20 rules out of several hundreds are enabled by default. The reason why there are so few rules enabled by default is that enabling more rules would possibly break a lot of builds out there that treat warnings as errors.

<TreatWarningsAsErrors>true</TreatWarningsAsErrors>

To enable more rules there's two main paths, enabling more rules in the project file or adding rule severity in the .editorconfig.

Configuration in the project file

To configure which rules are analysed, add the element AnalysisLevel to the project file.

  <PropertyGroup>
    <AnalysisLevel>latest-all</AnalysisLevel>
  </PropertyGroup>

The value for <AnalysisLevel> is made up of two parts, the version and the mode: <version>-<mode>. For instance the above will analyze all rules based on the latest version of the .NET SDK.

Version

The version specifies which rules to analyze based on the .NET version specified. Uses can be latest or the current version, preview any preview that might be installed, or any specific version such as 5.0 or 7.

Mode

Mode sets the amount of rules to analyze. The amount of rules include in order of increased amount of rules from none (disable all), default, minimum, recommended to all. It's a rather rough way of determining which rules that are used, but it will get you started.

Back in the .NET 5 SDK days, <AnalysisLevel> only contained the version and the mode was set using <AnalysisMode>. In .NET 6 support for the compound value was added, but the non-compount way is still supported.