Hello everyone. This is a small article about how PVS-Studio analyzes Blazor components. We'll try to anticipate your questions and answer them here. Enjoy!
What is the article about?
We've taught PVS-Studio to analyze code inside the components of Blazor applications. In this article, we'll tell you how we came up with this idea, how such analysis can help users, and what opportunities and limitations are in the current version. We also invite you to discuss this and upcoming features of PVS-Studio (more at the end of the article).
But first, let's refresh our memory about terminology.
Razor is markup syntax that allows you to implement C# code into a web page.
Razor markup is used by Blazor/Razor components (.razor files), as well as Razor Pages (.cshtml files). I'm specifying Blazor/Razor, since according to MSDN, both names are acceptable: "Blazor apps are built using Razor components, informally known as Blazor components".
So, this article is primarily about files with the .razor extension.
A .razor file is the main building block of the Blazor application. Razor components allow you to encapsulate business logic and view to form an element of a user interface. Each Razor component is an independent block, which allows you to use them to create new components and migrate them between projects.
Why do I, a user, need to analyze Razor components?
Web applications that use Blazor contain C# code in .razor files. Such code, like any other else, may contain errors, mistakes, and typos. They may be hard to find manually and expensive to fix at later stages of development. Now PVS-Studio analyzes Razor components, helping to make code stored there correct and safe.
Why didn't PVS-Studio know how to analyze .razor files before?
The analysis of .razor files was difficult due to the Razor markup constructs. They didn't allow to correctly obtain syntactic and semantic models respectively. Because of that, checking .razor files was not available "out of the box". Now we've enhanced the analyzer and taught it to check C# code in these files. As of now, the analyzer checks code only in the @code{...} blocks. We made this decision based on the combination of various factors. The main one — a desire to provide users with the analysis of Razor components as soon as possible, even if it's MVP.
Why did you decide to check .razor files?
We were thinking about the development of the C# analyzer and its directions, and concluded that the development should meet the needs of users. Many of them somehow related to web development. That's why we thought: "Why don't we expand the analyzer's functionality in web project analysis?". And voila — we added the analysis of .razor files.
Wait, there may be errors in .razor files?
Yes, they may be. Let's look at the most illustrative errors in .razor files of open-source projects. I found these errors during the quick check.
Issue 1:
....
RenderFragment<T> child() => item =>
@<text>
@{
var rowClass = new CssBuilder(RowClass)
.AddClass(RowClassFunc?.Invoke(item, rowIndex))
.AddClass(customClass,
!string.IsNullOrEmpty("mud-table-row-group-indented-1"))
.Build();
....
}
....
The analyzer issued the following warning: V3022 Expression '!string.IsNullOrEmpty("mud-table-row-group-indented-1")' is always true.
Let's start with a quite interesting warning issued on the MudBlazor project. The analyzer warns us that !string.IsNullOrEmpty("mud-table-row-group-indented-1") is always true. Can't argue with that, since a string literal cannot become empty or turn into null. It's hard to say what the developer intended to do here, but the code looks suspicious...
Issue 2:
@code
{
....
public void Evaluate()
{
....
var exp = new Expression(CalcExpression);
var result = exp.Eval();
if (result == double.NaN)
{
Current = "ERROR";
return;
}
Current = Math.Round( result,8).ToString(CultureInfo.InvariantCulture);
CalcExpression = Current;
}
....
}
The analyzer's warning: V3076 Comparison of 'result' with 'double.NaN' is meaningless. Use 'double.IsNaN()' method instead.
Let's inspect another case in the same project. The analyzer says that comparison with double.NaN is pointless. But why? According to MSDN, a comparison of two values of NaN via the '==' operator always returns false. To compare values correctly, you should use the double.IsNaN method.
Issue 3:
It's time to show our own mistakes. Yes, we also make mistakes and find them with our analyzer. After we implemented analysis of .razor files, the analyzer issued interesting warnings in the code of our internal utility.
@code
{
async Task Load()
{
var exceptionCustomers = string.Empty;
var exceptionTeam = string.Empty; <=
....
(CustomerNotifier, exceptionCustomers) = DbProvider.GetMailApplication(
CustomerCoreLibrary
.Data.Types
.ConfigMailApplicationType
.CustomerNotifier);
if (!string.IsNullOrEmpty(exceptionCustomers))
await MatDialogService.AlertAsync(exceptionCustomers);
(TeamNotifier, exceptionCustomers) = DbProvider.GetMailApplication(
CustomerCoreLibrary
.Data.Types
.ConfigMailApplicationType
.TeamNotifier);
if (!string.IsNullOrEmpty(exceptionTeam)) <=
await MatDialogService.AlertAsync(exceptionTeam);
....
}
}
The analyzer's warnings:
Here the analyzer issued two warnings which together fully describe the error.
First, the !string.IsNullOrEmpty(exceptionTeam) condition is always false. Indeed, the exceptionTeam variable is assigned an empty string and then the variable's value doesn't change until the check. But how did this code fragment appear? The second warning answers that question. It implies that there's a typo, and a wrong variable is used. Indeed! Absolutely correct.
I suggest we stop here — this article is not about the project check, but about the new analyzer feature. If you want to look for errors in .razor files of your projects, you can get a trial license here. Share interesting findings in comments.
What about the .cshtml files support?
As of now, we haven't implemented analysis of .cshtml files. However, that doesn't mean we're not going to implement it at all. If we see that our users are interested in this feature, we'll definitely try to support this format. If you are interested in analysis of .cshtml files, let us know.
In conclusion, I want to ask you a question. Do you use Blazor in your projects? Should we implement analysis of .cshtml files or is it a waste of time and effort?
Leave your thoughts about Razor and Blazor in the comments — I'll be glad to read your feedback.
0