New rules for Blazor in Meziantou.Analyzer

 
 
  • Gérald Barré

Static analysis is a great way to improve code quality and catch errors before they happen. Because Blazor has some dynamic parts, certain errors only surface at runtime. This post covers recent additions to Meziantou.Analyzer that detect these errors at compile time.

Meziantou.Analyzer is a NuGet package that provides a set of analyzers to improve the quality of your C# code. It currently contains 120 rules. Below are the new rules related to Blazor and Razor components.

#How to install Meziantou.Analyzer

Meziantou.Analyzer is available on NuGet. To install the package, you can use the following command:

Shell
dotnet add package Meziantou.Analyzer

This should add the following line to your .csproj file:

MSBuild project file
<PackageReference Include="Meziantou.Analyzer" Version="1.0.742">
  <PrivateAssets>all</PrivateAssets>
  <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>

#Meziantou Analyzer's Rules for Blazor

##Detect unknown component parameters

The MA0115 rule detects unknown component parameters. When you use unknown parameters, Blazor throws an exception at runtime. Detecting such errors only at runtime makes it harder to catch breaking changes when updating a package.

Let's consider a component MyComponent that accepts a Title parameter:

MyComponent.razor (Razor)
<h3>@Title</h3>

@code {
    [Parameter] public string Title { get; set; }
}

If you use this component with an unknown parameter, you'll get a warning:

Sample.razor (Razor)
@* This code compiles, but fails at runtime as "UnknownParameter" does not exist *@
<MyComponent Title="value" UnknownParameter="dummy" />

##Properties marked with [SupplyParameterFromQuery] attribute should also be marked as [Parameter]

The [SupplyParameterFromQuery] attribute specifies that a component parameter of a routable component can come from the query string. This attribute must be combined with the [Parameter] attribute to work correctly in Blazor. You can read more about Query Strings in Blazor in this documentation page.

The MA0116 will report a warning if the [Parameter] attribute is missing.

MyComponent.razor (Razor)
@code {
    [SupplyParameterFromQuery] // MA0116: Missing [Parameter] attribute
    public string? Value { get; set; }
}

##Properties marked with [SupplyParameterFromQuery] attribute are only valid in routable components

The [SupplyParameterFromQuery] attribute specifies that a component parameter of a routable component can come from the query string. A component is routable when @page is used in the component or the [Route("")] attribute is applied explicitly. You can read more about Query Strings in Blazor in this documentation page.

The MA0122 will report a warning if the component is not routable (@page is not defined).

MyComponent.razor (Razor)
@code {
    [Parameter, SupplyParameterFromQuery] // MA0122: @page is missing
    public string? Value { get; set; }
}

##Properties marked with [EditorRequired] attribute should also be marked as [Parameter]

The [EditorRequired] attribute specifies that a component parameter is mandatory. This attribute must be used in combination with the [Parameter] attribute to be used by Blazor. You can read more about this attribute in this documentation page.

The MA0117 will report a warning if the [Parameter] attribute is missing.

MyComponent.razor (Razor)
@code {
    [EditorRequired] // MA0117: Missing [Parameter] attribute
    public string? Value { get; set; }
}

##Methods marked with [JSInvokable] attribute must be public

Blazor allows you to call .NET code from JS. This is done using the [JSInvokable] attribute. The method you want to call from JS must be public and decorated with [JSInvokable].

The MA0118 reports a warning when a method is marked as [JSInvokable] but is not public.

C#
class Sample
{
    [JSInvokable] // MA0118: The method must be public
    internal static int[] ReturnArray()
    {
        return new int[] { 1, 2, 3 };
    }
}

##JSRuntime must not be used in OnInitialized or OnInitializedAsync

Unless you are using Blazor WebAssembly, the JSRuntime is not accessible in OnInitialized or OnInitializedAsync. If you try to use the JSRuntime in these methods, you'll get an error at runtime. This rule also detects types that use the JSRuntime under the hood, such as ProtectedBrowserStorage.

The MA0119 reports a warning if the JSRuntime is used in the OnInitialize or OnInitializeAsync methods. If Blazor WebAssembly is detected, the rule is disabled.

##Use InvokeVoidAsync instead of InvokeAsync when the return value is not used

The InvokeVoidAsync method calls a JS function without returning a result. It is more efficient than calling InvokeAsync and discarding the return value.

The MA0120 rule reports usages of IJSRuntime.InvokeAsync when the returned value is not used.

##Do not overwrite parameter values

Component parameters should not be set manually by the component after the component is rendered for the first time. The documentation explains the reasons for this in the Overwritten parameters section.

The MA0121 rule reports assignments to a parameter outside of the constructor, OnInitialized, and SetParametersAsync.

The rule is disabled by default as it may report false-positives. You need to enable it using an .editorconfig file:

[*.cs]
dotnet_diagnostic.MA0121.severity = warning

#Additional resources

Do you have a question or a suggestion about this post? Contact me!

Follow me:
Enjoy this blog?