From da98dcaf4daf854b282682df626e165101822223 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Fri, 27 Feb 2026 02:55:10 +0000
Subject: [PATCH 1/5] Initial plan
From b208f0afbec2a792c81f7b88afc5f707227af688 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Fri, 27 Feb 2026 03:27:56 +0000
Subject: [PATCH 2/5] feat: Add MA0187 - Use constructor injection instead of
[Inject] attribute in Blazor components
Co-authored-by: meziantou <509220+meziantou@users.noreply.github.com>
---
README.md | 1 +
docs/README.md | 7 +
docs/Rules/MA0187.md | 42 +++
.../BlazorPropertyInjectionFixAllProvider.cs | 63 +++++
...ctionShouldUseConstructorInjectionFixer.cs | 235 ++++++++++++++++
.../configuration/default.editorconfig | 3 +
.../configuration/none.editorconfig | 3 +
.../Internals/LanguageVersionExtensions.cs | 5 +
src/Meziantou.Analyzer/RuleIdentifiers.cs | 1 +
...onShouldUseConstructorInjectionAnalyzer.cs | 74 +++++
.../Helpers/ProjectBuilder.Validation.cs | 11 +-
.../Helpers/TargetFramework.cs | 1 +
...uldUseConstructorInjectionAnalyzerTests.cs | 256 ++++++++++++++++++
13 files changed, 701 insertions(+), 1 deletion(-)
create mode 100644 docs/Rules/MA0187.md
create mode 100644 src/Meziantou.Analyzer.CodeFixers/Rules/BlazorPropertyInjectionFixAllProvider.cs
create mode 100644 src/Meziantou.Analyzer.CodeFixers/Rules/BlazorPropertyInjectionShouldUseConstructorInjectionFixer.cs
create mode 100644 src/Meziantou.Analyzer/Rules/BlazorPropertyInjectionShouldUseConstructorInjectionAnalyzer.cs
create mode 100644 tests/Meziantou.Analyzer.Test/Rules/BlazorPropertyInjectionShouldUseConstructorInjectionAnalyzerTests.cs
diff --git a/README.md b/README.md
index d9f479fc9..7387c1f5e 100755
--- a/README.md
+++ b/README.md
@@ -201,6 +201,7 @@ If you are already using other analyzers, you can check [which rules are duplica
|[MA0184](https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0184.md)|Style|Do not use interpolated string without parameters|đģ|âī¸|âī¸|
|[MA0185](https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0185.md)|Performance|Simplify string.Create when all parameters are culture invariant|âšī¸|âī¸|âī¸|
|[MA0186](https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0186.md)|Design|Equals method should use \[NotNullWhen(true)\] on the parameter|âšī¸|â|â|
+|[MA0187](https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0187.md)|Design|Use constructor injection instead of \[Inject\] attribute|âšī¸|âī¸|âī¸|
diff --git a/docs/README.md b/docs/README.md
index 67803cce7..6a954814d 100755
--- a/docs/README.md
+++ b/docs/README.md
@@ -185,6 +185,7 @@
|[MA0184](https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0184.md)|Style|Do not use interpolated string without parameters|đģ|âī¸|âī¸|
|[MA0185](https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0185.md)|Performance|Simplify string.Create when all parameters are culture invariant|âšī¸|âī¸|âī¸|
|[MA0186](https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0186.md)|Design|Equals method should use \[NotNullWhen(true)\] on the parameter|âšī¸|â|â|
+|[MA0187](https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0187.md)|Design|Use constructor injection instead of \[Inject\] attribute|âšī¸|âī¸|âī¸|
|Id|Suppressed rule|Justification|
|--|---------------|-------------|
@@ -755,6 +756,9 @@ dotnet_diagnostic.MA0185.severity = suggestion
# MA0186: Equals method should use [NotNullWhen(true)] on the parameter
dotnet_diagnostic.MA0186.severity = none
+
+# MA0187: Use constructor injection instead of [Inject] attribute
+dotnet_diagnostic.MA0187.severity = suggestion
```
# .editorconfig - all rules disabled
@@ -1311,4 +1315,7 @@ dotnet_diagnostic.MA0185.severity = none
# MA0186: Equals method should use [NotNullWhen(true)] on the parameter
dotnet_diagnostic.MA0186.severity = none
+
+# MA0187: Use constructor injection instead of [Inject] attribute
+dotnet_diagnostic.MA0187.severity = none
```
diff --git a/docs/Rules/MA0187.md b/docs/Rules/MA0187.md
new file mode 100644
index 000000000..05eb597b4
--- /dev/null
+++ b/docs/Rules/MA0187.md
@@ -0,0 +1,42 @@
+# MA0187 - Use constructor injection instead of \[Inject\] attribute
+
+Sources: [BlazorPropertyInjectionShouldUseConstructorInjectionAnalyzer.cs](https://github.com/meziantou/Meziantou.Analyzer/blob/main/src/Meziantou.Analyzer/Rules/BlazorPropertyInjectionShouldUseConstructorInjectionAnalyzer.cs), [BlazorPropertyInjectionShouldUseConstructorInjectionFixer.cs](https://github.com/meziantou/Meziantou.Analyzer/blob/main/src/Meziantou.Analyzer.CodeFixers/Rules/BlazorPropertyInjectionShouldUseConstructorInjectionFixer.cs)
+
+
+Since .NET 9, Blazor components support constructor injection. This is preferred over property injection via the `[Inject]` attribute as it avoids the need for `= default!` initializers and makes dependencies explicit.
+
+This rule only applies when:
+- The ASP.NET Core version is 9.0 or greater
+- The C# language version is 12 or greater (required for primary constructors)
+- The class does not have explicit non-primary constructors
+
+## Non-compliant code
+
+```csharp
+using Microsoft.AspNetCore.Components;
+
+class MyComponent : ComponentBase
+{
+ [Inject]
+ protected NavigationManager Navigation { get; set; } = default!;
+
+ private void HandleClick()
+ {
+ Navigation.NavigateTo("/counter");
+ }
+}
+```
+
+## Compliant code
+
+```csharp
+using Microsoft.AspNetCore.Components;
+
+class MyComponent(NavigationManager navigation) : ComponentBase
+{
+ private void HandleClick()
+ {
+ navigation.NavigateTo("/counter");
+ }
+}
+```
diff --git a/src/Meziantou.Analyzer.CodeFixers/Rules/BlazorPropertyInjectionFixAllProvider.cs b/src/Meziantou.Analyzer.CodeFixers/Rules/BlazorPropertyInjectionFixAllProvider.cs
new file mode 100644
index 000000000..f9e0a7641
--- /dev/null
+++ b/src/Meziantou.Analyzer.CodeFixers/Rules/BlazorPropertyInjectionFixAllProvider.cs
@@ -0,0 +1,63 @@
+using System.Collections.Immutable;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CodeActions;
+using Microsoft.CodeAnalysis.CodeFixes;
+
+namespace Meziantou.Analyzer.Rules;
+
+internal sealed class BlazorPropertyInjectionFixAllProvider : FixAllProvider
+{
+ public static readonly BlazorPropertyInjectionFixAllProvider Instance = new();
+
+ public override async Task GetFixAsync(FixAllContext fixAllContext)
+ {
+ var diagnosticsToFix = await fixAllContext.GetAllDiagnosticsAsync(fixAllContext.Project).ConfigureAwait(false);
+ if (diagnosticsToFix.IsEmpty)
+ return null;
+
+ return CodeAction.Create(
+ "Use constructor injection",
+ ct => FixAllAsync(fixAllContext, diagnosticsToFix, ct),
+ equivalenceKey: "Use constructor injection");
+ }
+
+ private static async Task FixAllAsync(FixAllContext fixAllContext, ImmutableArray diagnostics, CancellationToken cancellationToken)
+ {
+ var solution = fixAllContext.Project.Solution;
+
+ // Group diagnostics by document
+ var diagnosticsByDocument = new Dictionary>();
+ foreach (var diagnostic in diagnostics)
+ {
+ if (diagnostic.Location.IsInSource)
+ {
+ var document = solution.GetDocument(diagnostic.Location.SourceTree);
+ if (document is not null)
+ {
+ if (!diagnosticsByDocument.TryGetValue(document.Id, out var list))
+ {
+ list = [];
+ diagnosticsByDocument[document.Id] = list;
+ }
+
+ list.Add(diagnostic);
+ }
+ }
+ }
+
+ // Process each document
+ foreach (var (documentId, documentDiagnostics) in diagnosticsByDocument)
+ {
+ var document = solution.GetDocument(documentId);
+ if (document is null)
+ continue;
+
+ solution = await BlazorPropertyInjectionShouldUseConstructorInjectionFixer.FixDocumentAsync(
+ document,
+ [.. documentDiagnostics],
+ cancellationToken).ConfigureAwait(false);
+ }
+
+ return solution;
+ }
+}
diff --git a/src/Meziantou.Analyzer.CodeFixers/Rules/BlazorPropertyInjectionShouldUseConstructorInjectionFixer.cs b/src/Meziantou.Analyzer.CodeFixers/Rules/BlazorPropertyInjectionShouldUseConstructorInjectionFixer.cs
new file mode 100644
index 000000000..e6d2114af
--- /dev/null
+++ b/src/Meziantou.Analyzer.CodeFixers/Rules/BlazorPropertyInjectionShouldUseConstructorInjectionFixer.cs
@@ -0,0 +1,235 @@
+using System.Collections.Immutable;
+using System.Composition;
+using System.Text;
+using Meziantou.Analyzer.Internals;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CodeActions;
+using Microsoft.CodeAnalysis.CodeFixes;
+using Microsoft.CodeAnalysis.CSharp;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Microsoft.CodeAnalysis.Rename;
+using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
+
+namespace Meziantou.Analyzer.Rules;
+
+[ExportCodeFixProvider(LanguageNames.CSharp), Shared]
+public sealed class BlazorPropertyInjectionShouldUseConstructorInjectionFixer : CodeFixProvider
+{
+ public override ImmutableArray FixableDiagnosticIds =>
+ ImmutableArray.Create(RuleIdentifiers.BlazorPropertyInjectionShouldUseConstructorInjection);
+
+ public override FixAllProvider GetFixAllProvider() =>
+ BlazorPropertyInjectionFixAllProvider.Instance;
+
+ public override async Task RegisterCodeFixesAsync(CodeFixContext context)
+ {
+ var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);
+ var nodeToFix = root?.FindNode(context.Span, getInnermostNodeForTie: true);
+ if (nodeToFix is null)
+ return;
+
+ var title = "Use constructor injection";
+ context.RegisterCodeFix(
+ CodeAction.Create(
+ title,
+ ct => FixDocumentAsync(context.Document, context.Diagnostics, ct),
+ equivalenceKey: title),
+ context.Diagnostics);
+ }
+
+ internal static async Task FixDocumentAsync(Document document, ImmutableArray diagnostics, CancellationToken cancellationToken)
+ {
+ var solution = document.Project.Solution;
+ var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
+ var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);
+ if (root is null || semanticModel is null)
+ return solution;
+
+ // Collect all (property symbol, parameter name) pairs from the diagnostics
+ var propertiesToFix = new List<(IPropertySymbol Symbol, string ParameterName, TypeSyntax PropertyType)>();
+ foreach (var diagnostic in diagnostics)
+ {
+ var node = root.FindNode(diagnostic.Location.SourceSpan, getInnermostNodeForTie: true);
+ var propertyDecl = node?.AncestorsAndSelf().OfType().FirstOrDefault();
+ if (propertyDecl is null)
+ continue;
+
+ var propertySymbol = semanticModel.GetDeclaredSymbol(propertyDecl, cancellationToken) as IPropertySymbol;
+ if (propertySymbol is null)
+ continue;
+
+ var classDecl = propertyDecl.Ancestors().OfType().FirstOrDefault();
+ if (classDecl is null || HasExplicitNonPrimaryConstructors(classDecl))
+ continue;
+
+ var parameterName = ComputeParameterName(propertySymbol.Name);
+ propertiesToFix.Add((propertySymbol, parameterName, propertyDecl.Type.WithoutTrivia()));
+ }
+
+ if (propertiesToFix.Count == 0)
+ return solution;
+
+ // Group by containing class (to handle multiple properties in the same class)
+ var byClass = propertiesToFix.GroupBy(p => p.Symbol.ContainingType, SymbolEqualityComparer.Default).ToList();
+
+ foreach (var classGroup in byClass)
+ {
+ var properties = classGroup.ToList();
+ var firstClassDecl = await GetClassDeclarationAsync(document, solution, properties[0].Symbol, cancellationToken).ConfigureAwait(false);
+ if (firstClassDecl is null)
+ continue;
+
+ // Annotate the class so we can find it after all renames
+ document = solution.GetDocument(document.Id)!;
+ root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
+ if (root is null)
+ continue;
+
+ var classAnnotation = new SyntaxAnnotation();
+ var classDeclNode = root.DescendantNodesAndSelf().OfType()
+ .FirstOrDefault(t => t.Identifier.ValueText == firstClassDecl.Identifier.ValueText);
+ if (classDeclNode is null)
+ continue;
+
+ root = root.ReplaceNode(classDeclNode, classDeclNode.WithAdditionalAnnotations(classAnnotation));
+ document = document.WithSyntaxRoot(root);
+ solution = document.Project.Solution;
+
+ // Rename each property sequentially; find each by its current identifier
+ // After each rename, the property name changes but the type stays the same
+ var parameterNames = properties.Select(p => p.ParameterName).ToHashSet(StringComparer.Ordinal);
+
+ foreach (var (propSymbol, paramName, _) in properties)
+ {
+ // Get fresh state for each rename
+ document = solution.GetDocument(document.Id)!;
+ root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
+ semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);
+ if (root is null || semanticModel is null)
+ continue;
+
+ // Find the class by annotation
+ var currentClassDecl = root.GetAnnotatedNodes(classAnnotation).OfType().FirstOrDefault();
+ if (currentClassDecl is null)
+ continue;
+
+ // Find the property by original name (propSymbol.Name is the original name)
+ var currentPropDecl = currentClassDecl.Members
+ .OfType()
+ .FirstOrDefault(p => p.Identifier.ValueText == propSymbol.Name);
+ if (currentPropDecl is null)
+ continue;
+
+ var currentPropSymbol = semanticModel.GetDeclaredSymbol(currentPropDecl, cancellationToken) as IPropertySymbol;
+ if (currentPropSymbol is null)
+ continue;
+
+ // Rename using Renamer
+ solution = await Renamer.RenameSymbolAsync(solution, currentPropSymbol, new SymbolRenameOptions(), paramName, cancellationToken).ConfigureAwait(false);
+ }
+
+ // After all renames, apply structural changes to the class
+ document = solution.GetDocument(document.Id)!;
+ root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
+ if (root is null)
+ continue;
+
+ var updatedClassDecl = root.GetAnnotatedNodes(classAnnotation).OfType().FirstOrDefault();
+ if (updatedClassDecl is null)
+ continue;
+
+ // Find all renamed [Inject] properties (now with camelCase identifiers)
+ var renamedProperties = updatedClassDecl.Members
+ .OfType()
+ .Where(p => parameterNames.Contains(p.Identifier.ValueText))
+ .ToList();
+
+ // Build parameter list from original type info (ordered same as diagnostics)
+ var newParams = properties
+ .Select(p => Parameter(
+ List(),
+ TokenList(),
+ p.PropertyType,
+ Identifier(p.ParameterName),
+ null))
+ .ToList();
+
+ TypeDeclarationSyntax newClassDecl;
+ if (updatedClassDecl.ParameterList is not null)
+ {
+ var existingParams = updatedClassDecl.ParameterList.Parameters;
+ ParameterListSyntax newParamList;
+ if (existingParams.Count > 0)
+ {
+ var paramsWithSeparator = newParams.Select(p => p.WithLeadingTrivia(Space));
+ newParamList = updatedClassDecl.ParameterList.AddParameters([.. paramsWithSeparator]);
+ }
+ else
+ {
+ newParamList = updatedClassDecl.ParameterList.WithParameters(
+ SeparatedList(newParams, Enumerable.Repeat(Token(SyntaxKind.CommaToken).WithTrailingTrivia(Space), newParams.Count - 1)));
+ }
+
+ newClassDecl = updatedClassDecl.WithParameterList(newParamList);
+ }
+ else
+ {
+ var newParamList = ParameterList(
+ SeparatedList(newParams, Enumerable.Repeat(Token(SyntaxKind.CommaToken).WithTrailingTrivia(Space), newParams.Count - 1)));
+ newClassDecl = updatedClassDecl.WithParameterList(newParamList);
+ }
+
+ // Remove all renamed [Inject] properties
+ foreach (var renamedProp in renamedProperties)
+ {
+ var propToRemove = newClassDecl.Members
+ .OfType()
+ .FirstOrDefault(p => p.Identifier.ValueText == renamedProp.Identifier.ValueText);
+ if (propToRemove is not null)
+ {
+ newClassDecl = newClassDecl.RemoveNode(propToRemove, SyntaxRemoveOptions.KeepNoTrivia)!;
+ }
+ }
+
+ root = root.ReplaceNode(updatedClassDecl, newClassDecl);
+ document = document.WithSyntaxRoot(root);
+ solution = document.Project.Solution;
+ }
+
+ return solution;
+ }
+
+ private static async Task GetClassDeclarationAsync(Document document, Solution solution, IPropertySymbol propertySymbol, CancellationToken cancellationToken)
+ {
+ var doc = solution.GetDocument(document.Id)!;
+ var root = await doc.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
+ if (root is null)
+ return null;
+
+ var semanticModel = await doc.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);
+ if (semanticModel is null)
+ return null;
+
+ return root.DescendantNodes().OfType()
+ .FirstOrDefault(t =>
+ {
+ var symbol = semanticModel.GetDeclaredSymbol(t, cancellationToken);
+ return SymbolEqualityComparer.Default.Equals(symbol, propertySymbol.ContainingType);
+ });
+ }
+
+ private static bool HasExplicitNonPrimaryConstructors(TypeDeclarationSyntax typeDeclaration)
+ {
+ return typeDeclaration.Members.OfType().Any();
+ }
+
+ internal static string ComputeParameterName(string propertyName)
+ {
+ if (string.IsNullOrEmpty(propertyName))
+ return propertyName;
+
+ var sb = new StringBuilder(propertyName);
+ sb[0] = char.ToLowerInvariant(sb[0]);
+ return sb.ToString();
+ }
+}
diff --git a/src/Meziantou.Analyzer.Pack/configuration/default.editorconfig b/src/Meziantou.Analyzer.Pack/configuration/default.editorconfig
index dc1a96a46..b1307e84a 100644
--- a/src/Meziantou.Analyzer.Pack/configuration/default.editorconfig
+++ b/src/Meziantou.Analyzer.Pack/configuration/default.editorconfig
@@ -553,3 +553,6 @@ dotnet_diagnostic.MA0185.severity = suggestion
# MA0186: Equals method should use [NotNullWhen(true)] on the parameter
dotnet_diagnostic.MA0186.severity = none
+
+# MA0187: Use constructor injection instead of [Inject] attribute
+dotnet_diagnostic.MA0187.severity = suggestion
diff --git a/src/Meziantou.Analyzer.Pack/configuration/none.editorconfig b/src/Meziantou.Analyzer.Pack/configuration/none.editorconfig
index 1c12ff8e3..cca6726d6 100644
--- a/src/Meziantou.Analyzer.Pack/configuration/none.editorconfig
+++ b/src/Meziantou.Analyzer.Pack/configuration/none.editorconfig
@@ -553,3 +553,6 @@ dotnet_diagnostic.MA0185.severity = none
# MA0186: Equals method should use [NotNullWhen(true)] on the parameter
dotnet_diagnostic.MA0186.severity = none
+
+# MA0187: Use constructor injection instead of [Inject] attribute
+dotnet_diagnostic.MA0187.severity = none
diff --git a/src/Meziantou.Analyzer/Internals/LanguageVersionExtensions.cs b/src/Meziantou.Analyzer/Internals/LanguageVersionExtensions.cs
index c20152426..a4b3ac030 100644
--- a/src/Meziantou.Analyzer/Internals/LanguageVersionExtensions.cs
+++ b/src/Meziantou.Analyzer/Internals/LanguageVersionExtensions.cs
@@ -24,6 +24,11 @@ public static bool IsCSharp14OrAbove(this LanguageVersion languageVersion)
return languageVersion >= (LanguageVersion)1400;
}
+ public static bool IsCSharp12OrAbove(this LanguageVersion languageVersion)
+ {
+ return languageVersion >= LanguageVersion.CSharp12;
+ }
+
public static bool IsCSharp8OrAbove(this LanguageVersion languageVersion)
{
return languageVersion >= LanguageVersion.CSharp8;
diff --git a/src/Meziantou.Analyzer/RuleIdentifiers.cs b/src/Meziantou.Analyzer/RuleIdentifiers.cs
index 314aa7f8f..95da6fa0a 100755
--- a/src/Meziantou.Analyzer/RuleIdentifiers.cs
+++ b/src/Meziantou.Analyzer/RuleIdentifiers.cs
@@ -186,6 +186,7 @@ internal static class RuleIdentifiers
public const string DoNotUseInterpolatedStringWithoutParameters = "MA0184";
public const string SimplifyStringCreateWhenAllParametersAreCultureInvariant = "MA0185";
public const string MissingNotNullWhenAttributeOnEquals = "MA0186";
+ public const string BlazorPropertyInjectionShouldUseConstructorInjection = "MA0187";
public static string GetHelpUri(string identifier)
{
diff --git a/src/Meziantou.Analyzer/Rules/BlazorPropertyInjectionShouldUseConstructorInjectionAnalyzer.cs b/src/Meziantou.Analyzer/Rules/BlazorPropertyInjectionShouldUseConstructorInjectionAnalyzer.cs
new file mode 100644
index 000000000..5bfa371e1
--- /dev/null
+++ b/src/Meziantou.Analyzer/Rules/BlazorPropertyInjectionShouldUseConstructorInjectionAnalyzer.cs
@@ -0,0 +1,74 @@
+using System;
+using System.Collections.Immutable;
+using Meziantou.Analyzer.Internals;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp;
+using Microsoft.CodeAnalysis.Diagnostics;
+
+namespace Meziantou.Analyzer.Rules;
+
+[DiagnosticAnalyzer(LanguageNames.CSharp)]
+public sealed class BlazorPropertyInjectionShouldUseConstructorInjectionAnalyzer : DiagnosticAnalyzer
+{
+ private static readonly DiagnosticDescriptor Rule = new(
+ RuleIdentifiers.BlazorPropertyInjectionShouldUseConstructorInjection,
+ title: "Use constructor injection instead of [Inject] attribute",
+ messageFormat: "Use constructor injection instead of [Inject] attribute",
+ RuleCategories.Design,
+ DiagnosticSeverity.Info,
+ isEnabledByDefault: true,
+ description: "",
+ helpLinkUri: RuleIdentifiers.GetHelpUri(RuleIdentifiers.BlazorPropertyInjectionShouldUseConstructorInjection));
+
+ public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(Rule);
+
+ public override void Initialize(AnalysisContext context)
+ {
+ context.EnableConcurrentExecution();
+ context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
+
+ context.RegisterCompilationStartAction(ctx =>
+ {
+ var analyzerContext = new AnalyzerContext(ctx.Compilation);
+ if (analyzerContext.IsValid)
+ {
+ ctx.RegisterSymbolAction(analyzerContext.AnalyzeProperty, SymbolKind.Property);
+ }
+ });
+ }
+
+ private sealed class AnalyzerContext
+ {
+ private static readonly Version Version9 = new(9, 0, 0, 0);
+
+ public AnalyzerContext(Compilation compilation)
+ {
+ InjectAttributeSymbol = compilation.GetBestTypeByMetadataName("Microsoft.AspNetCore.Components.InjectAttribute");
+ IComponentSymbol = compilation.GetBestTypeByMetadataName("Microsoft.AspNetCore.Components.IComponent");
+ }
+
+ public INamedTypeSymbol? InjectAttributeSymbol { get; }
+ public INamedTypeSymbol? IComponentSymbol { get; }
+
+ public bool IsValid =>
+ InjectAttributeSymbol is not null &&
+ IComponentSymbol is not null &&
+ InjectAttributeSymbol.ContainingAssembly.Identity.Version >= Version9;
+
+ public void AnalyzeProperty(SymbolAnalysisContext context)
+ {
+ if (context.Compilation.GetCSharpLanguageVersion() < LanguageVersion.CSharp12)
+ return;
+
+ var property = (IPropertySymbol)context.Symbol;
+
+ if (!property.HasAttribute(InjectAttributeSymbol, inherits: false))
+ return;
+
+ if (!property.ContainingType.IsOrImplements(IComponentSymbol))
+ return;
+
+ context.ReportDiagnostic(Rule, property);
+ }
+ }
+}
diff --git a/tests/Meziantou.Analyzer.Test/Helpers/ProjectBuilder.Validation.cs b/tests/Meziantou.Analyzer.Test/Helpers/ProjectBuilder.Validation.cs
index eabba2696..828b63f29 100755
--- a/tests/Meziantou.Analyzer.Test/Helpers/ProjectBuilder.Validation.cs
+++ b/tests/Meziantou.Analyzer.Test/Helpers/ProjectBuilder.Validation.cs
@@ -223,6 +223,11 @@ private Task CreateProject()
AddNuGetReference("Microsoft.AspNetCore.App.Ref", "8.0.0", "ref/net8.0/");
break;
+ case TargetFramework.AspNetCore9_0:
+ AddNuGetReference("Microsoft.NETCore.App.Ref", "9.0.0", "ref/net9.0/");
+ AddNuGetReference("Microsoft.AspNetCore.App.Ref", "9.0.0", "ref/net9.0/");
+ break;
+
case TargetFramework.WindowsDesktop5_0:
AddNuGetReference("Microsoft.WindowsDesktop.App.Ref", "5.0.0", "ref/net5.0/");
break;
@@ -242,6 +247,10 @@ private Task CreateProject()
WithSourceGeneratorsFromNuGet("Microsoft.NETCore.App.Ref", "8.0.0", "analyzers/dotnet/cs/");
break;
+ case TargetFramework.AspNetCore9_0:
+ WithSourceGeneratorsFromNuGet("Microsoft.NETCore.App.Ref", "9.0.0", "analyzers/dotnet/cs/");
+ break;
+
case TargetFramework.Net9_0:
WithSourceGeneratorsFromNuGet("Microsoft.NETCore.App.Ref", "9.0.0", "analyzers/dotnet/cs/");
break;
@@ -253,7 +262,7 @@ private Task CreateProject()
}
- if (TargetFramework is not TargetFramework.Net7_0 and not TargetFramework.Net8_0 and not TargetFramework.Net9_0 and not TargetFramework.Net10_0)
+ if (TargetFramework is not TargetFramework.Net7_0 and not TargetFramework.Net8_0 and not TargetFramework.Net9_0 and not TargetFramework.Net10_0 and not TargetFramework.AspNetCore9_0)
{
AddNuGetReference("System.Collections.Immutable", "1.5.0", "lib/netstandard2.0/");
AddNuGetReference("System.Numerics.Vectors", "4.5.0", "ref/netstandard2.0/");
diff --git a/tests/Meziantou.Analyzer.Test/Helpers/TargetFramework.cs b/tests/Meziantou.Analyzer.Test/Helpers/TargetFramework.cs
index 001971195..29c3364dd 100644
--- a/tests/Meziantou.Analyzer.Test/Helpers/TargetFramework.cs
+++ b/tests/Meziantou.Analyzer.Test/Helpers/TargetFramework.cs
@@ -17,5 +17,6 @@ public enum TargetFramework
AspNetCore6_0,
AspNetCore7_0,
AspNetCore8_0,
+ AspNetCore9_0,
WindowsDesktop5_0,
}
diff --git a/tests/Meziantou.Analyzer.Test/Rules/BlazorPropertyInjectionShouldUseConstructorInjectionAnalyzerTests.cs b/tests/Meziantou.Analyzer.Test/Rules/BlazorPropertyInjectionShouldUseConstructorInjectionAnalyzerTests.cs
new file mode 100644
index 000000000..a6b07a2db
--- /dev/null
+++ b/tests/Meziantou.Analyzer.Test/Rules/BlazorPropertyInjectionShouldUseConstructorInjectionAnalyzerTests.cs
@@ -0,0 +1,256 @@
+using Meziantou.Analyzer.Rules;
+using Meziantou.Analyzer.Test.Helpers;
+using Microsoft.CodeAnalysis.CSharp;
+using TestHelper;
+
+namespace Meziantou.Analyzer.Test.Rules;
+
+public sealed class BlazorPropertyInjectionShouldUseConstructorInjectionAnalyzerTests
+{
+ private static ProjectBuilder CreateProjectBuilder()
+ {
+ return new ProjectBuilder()
+ .WithAnalyzer()
+ .WithCodeFixProvider()
+ .WithTargetFramework(TargetFramework.AspNetCore9_0)
+ .WithLanguageVersion(LanguageVersion.CSharp12);
+ }
+
+ [Fact]
+ public async Task InjectProperty_IComponent_ReportsDiagnostic()
+ {
+ await CreateProjectBuilder()
+ .WithSourceCode("""
+using Microsoft.AspNetCore.Components;
+
+class MyComponent : IComponent
+{
+ [Inject]
+ protected NavigationManager [||]Navigation { get; set; } = default!;
+
+ public void Attach(RenderHandle renderHandle) { }
+ public System.Threading.Tasks.Task SetParametersAsync(ParameterView parameters) => System.Threading.Tasks.Task.CompletedTask;
+}
+""")
+ .ShouldFixCodeWith("""
+using Microsoft.AspNetCore.Components;
+
+class MyComponent(NavigationManager navigation) : IComponent
+{
+
+ public void Attach(RenderHandle renderHandle) { }
+ public System.Threading.Tasks.Task SetParametersAsync(ParameterView parameters) => System.Threading.Tasks.Task.CompletedTask;
+}
+""")
+ .ValidateAsync();
+ }
+
+ [Fact]
+ public async Task InjectProperty_ComponentBase_ReportsDiagnostic()
+ {
+ await CreateProjectBuilder()
+ .WithSourceCode("""
+using Microsoft.AspNetCore.Components;
+
+class MyComponent : ComponentBase
+{
+ [Inject]
+ protected NavigationManager [||]Navigation { get; set; } = default!;
+}
+""")
+ .ShouldFixCodeWith("""
+using Microsoft.AspNetCore.Components;
+
+class MyComponent(NavigationManager navigation) : ComponentBase
+{
+}
+""")
+ .ValidateAsync();
+ }
+
+ [Fact]
+ public async Task InjectProperty_ExistingPrimaryConstructor_AddsParameter()
+ {
+ await CreateProjectBuilder()
+ .WithSourceCode("""
+using Microsoft.AspNetCore.Components;
+using Microsoft.Extensions.Logging;
+
+class MyComponent(ILogger logger) : ComponentBase
+{
+ [Inject]
+ protected NavigationManager [||]Navigation { get; set; } = default!;
+}
+""")
+ .ShouldFixCodeWith("""
+using Microsoft.AspNetCore.Components;
+using Microsoft.Extensions.Logging;
+
+class MyComponent(ILogger logger, NavigationManager navigation) : ComponentBase
+{
+}
+""")
+ .ValidateAsync();
+ }
+
+ [Fact]
+ public async Task InjectProperty_WithExplicitConstructor_NoDiagnosticFix()
+ {
+ // Analyzer still reports, but no code fix when explicit non-primary constructor exists
+ await CreateProjectBuilder()
+ .WithSourceCode("""
+using Microsoft.AspNetCore.Components;
+
+class MyComponent : ComponentBase
+{
+ public MyComponent() { }
+
+ [Inject]
+ protected NavigationManager [||]Navigation { get; set; } = default!;
+}
+""")
+ .ValidateAsync();
+ }
+
+ [Fact]
+ public async Task NoInjectAttribute_NoDiagnostic()
+ {
+ await CreateProjectBuilder()
+ .WithSourceCode("""
+using Microsoft.AspNetCore.Components;
+
+class MyComponent : ComponentBase
+{
+ protected NavigationManager Navigation { get; set; } = default!;
+}
+""")
+ .ValidateAsync();
+ }
+
+ [Fact]
+ public async Task InjectProperty_NotBlazorComponent_NoDiagnostic()
+ {
+ await CreateProjectBuilder()
+ .WithSourceCode("""
+using Microsoft.AspNetCore.Components;
+
+class NotAComponent
+{
+ [Inject]
+ protected NavigationManager Navigation { get; set; } = default!;
+}
+""")
+ .ValidateAsync();
+ }
+
+ [Fact]
+ public async Task InjectProperty_CSharp11_NoDiagnostic()
+ {
+ await new ProjectBuilder()
+ .WithAnalyzer()
+ .WithTargetFramework(TargetFramework.AspNetCore9_0)
+ .WithLanguageVersion(LanguageVersion.CSharp11)
+ .WithSourceCode("""
+using Microsoft.AspNetCore.Components;
+
+class MyComponent : ComponentBase
+{
+ [Inject]
+ protected NavigationManager Navigation { get; set; } = default!;
+}
+""")
+ .ValidateAsync();
+ }
+
+ [Fact]
+ public async Task InjectProperty_AspNetCore8_NoDiagnostic()
+ {
+ await new ProjectBuilder()
+ .WithAnalyzer()
+ .WithTargetFramework(TargetFramework.AspNetCore8_0)
+ .WithLanguageVersion(LanguageVersion.CSharp12)
+ .WithSourceCode("""
+using Microsoft.AspNetCore.Components;
+
+class MyComponent : ComponentBase
+{
+ [Inject]
+ protected NavigationManager Navigation { get; set; } = default!;
+}
+""")
+ .ValidateAsync();
+ }
+
+ [Fact]
+ public async Task InjectProperty_UpdatesUsages()
+ {
+ await CreateProjectBuilder()
+ .WithSourceCode("""
+using Microsoft.AspNetCore.Components;
+
+class MyComponent : ComponentBase
+{
+ [Inject]
+ protected NavigationManager [||]Navigation { get; set; } = default!;
+
+ private void HandleClick()
+ {
+ Navigation.NavigateTo("/counter");
+ }
+}
+""")
+ .ShouldFixCodeWith("""
+using Microsoft.AspNetCore.Components;
+
+class MyComponent(NavigationManager navigation) : ComponentBase
+{
+
+ private void HandleClick()
+ {
+ navigation.NavigateTo("/counter");
+ }
+}
+""")
+ .ValidateAsync();
+ }
+
+ [Fact]
+ public async Task MultipleInjectProperties_BatchFix()
+ {
+ await CreateProjectBuilder()
+ .WithSourceCode("""
+using Microsoft.AspNetCore.Components;
+using Microsoft.Extensions.Logging;
+
+class MyComponent : ComponentBase
+{
+ [Inject]
+ protected NavigationManager [||]Navigation { get; set; } = default!;
+
+ [Inject]
+ protected ILogger [||]Logger { get; set; } = default!;
+
+ private void HandleClick()
+ {
+ Navigation.NavigateTo("/counter");
+ Logger.LogInformation("Clicked");
+ }
+}
+""")
+ .ShouldBatchFixCodeWith("""
+using Microsoft.AspNetCore.Components;
+using Microsoft.Extensions.Logging;
+
+class MyComponent(NavigationManager navigation, ILogger logger) : ComponentBase
+{
+
+ private void HandleClick()
+ {
+ navigation.NavigateTo("/counter");
+ logger.LogInformation("Clicked");
+ }
+}
+""")
+ .ValidateAsync();
+ }
+}
From 9779b7919b498379b293cc73682a7059f599e6ab Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Fri, 27 Feb 2026 04:19:55 +0000
Subject: [PATCH 3/5] Address review feedback: move IsCSharp12OrAbove, use
numeric version, disable by default
Co-authored-by: meziantou <509220+meziantou@users.noreply.github.com>
---
README.md | 2 +-
docs/README.md | 4 ++--
docs/Rules/MA0187.md | 9 +++++++++
.../configuration/default.editorconfig | 2 +-
.../Internals/LanguageVersionExtensions.cs | 10 +++++-----
...tyInjectionShouldUseConstructorInjectionAnalyzer.cs | 4 ++--
6 files changed, 20 insertions(+), 11 deletions(-)
diff --git a/README.md b/README.md
index 7387c1f5e..9d50f72b3 100755
--- a/README.md
+++ b/README.md
@@ -201,7 +201,7 @@ If you are already using other analyzers, you can check [which rules are duplica
|[MA0184](https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0184.md)|Style|Do not use interpolated string without parameters|đģ|âī¸|âī¸|
|[MA0185](https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0185.md)|Performance|Simplify string.Create when all parameters are culture invariant|âšī¸|âī¸|âī¸|
|[MA0186](https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0186.md)|Design|Equals method should use \[NotNullWhen(true)\] on the parameter|âšī¸|â|â|
-|[MA0187](https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0187.md)|Design|Use constructor injection instead of \[Inject\] attribute|âšī¸|âī¸|âī¸|
+|[MA0187](https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0187.md)|Design|Use constructor injection instead of \[Inject\] attribute|âšī¸|â|âī¸|
diff --git a/docs/README.md b/docs/README.md
index 6a954814d..832ad560f 100755
--- a/docs/README.md
+++ b/docs/README.md
@@ -185,7 +185,7 @@
|[MA0184](https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0184.md)|Style|Do not use interpolated string without parameters|đģ|âī¸|âī¸|
|[MA0185](https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0185.md)|Performance|Simplify string.Create when all parameters are culture invariant|âšī¸|âī¸|âī¸|
|[MA0186](https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0186.md)|Design|Equals method should use \[NotNullWhen(true)\] on the parameter|âšī¸|â|â|
-|[MA0187](https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0187.md)|Design|Use constructor injection instead of \[Inject\] attribute|âšī¸|âī¸|âī¸|
+|[MA0187](https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0187.md)|Design|Use constructor injection instead of \[Inject\] attribute|âšī¸|â|âī¸|
|Id|Suppressed rule|Justification|
|--|---------------|-------------|
@@ -758,7 +758,7 @@ dotnet_diagnostic.MA0185.severity = suggestion
dotnet_diagnostic.MA0186.severity = none
# MA0187: Use constructor injection instead of [Inject] attribute
-dotnet_diagnostic.MA0187.severity = suggestion
+dotnet_diagnostic.MA0187.severity = none
```
# .editorconfig - all rules disabled
diff --git a/docs/Rules/MA0187.md b/docs/Rules/MA0187.md
index 05eb597b4..ff0ab5461 100644
--- a/docs/Rules/MA0187.md
+++ b/docs/Rules/MA0187.md
@@ -40,3 +40,12 @@ class MyComponent(NavigationManager navigation) : ComponentBase
}
}
```
+
+## Configuration
+
+This rule is disabled by default. You can enable it by setting the severity in your `.editorconfig` file:
+
+```editorconfig
+# MA0187: Use constructor injection instead of [Inject] attribute
+dotnet_diagnostic.MA0187.severity = suggestion
+```
diff --git a/src/Meziantou.Analyzer.Pack/configuration/default.editorconfig b/src/Meziantou.Analyzer.Pack/configuration/default.editorconfig
index b1307e84a..cc2a14297 100644
--- a/src/Meziantou.Analyzer.Pack/configuration/default.editorconfig
+++ b/src/Meziantou.Analyzer.Pack/configuration/default.editorconfig
@@ -555,4 +555,4 @@ dotnet_diagnostic.MA0185.severity = suggestion
dotnet_diagnostic.MA0186.severity = none
# MA0187: Use constructor injection instead of [Inject] attribute
-dotnet_diagnostic.MA0187.severity = suggestion
+dotnet_diagnostic.MA0187.severity = none
diff --git a/src/Meziantou.Analyzer/Internals/LanguageVersionExtensions.cs b/src/Meziantou.Analyzer/Internals/LanguageVersionExtensions.cs
index a4b3ac030..9002e5ddd 100644
--- a/src/Meziantou.Analyzer/Internals/LanguageVersionExtensions.cs
+++ b/src/Meziantou.Analyzer/Internals/LanguageVersionExtensions.cs
@@ -14,6 +14,11 @@ public static bool IsCSharp11OrAbove(this LanguageVersion languageVersion)
return languageVersion >= (LanguageVersion)1100;
}
+ public static bool IsCSharp12OrAbove(this LanguageVersion languageVersion)
+ {
+ return languageVersion >= (LanguageVersion)1200;
+ }
+
public static bool IsCSharp13OrAbove(this LanguageVersion languageVersion)
{
return languageVersion >= (LanguageVersion)1300;
@@ -24,11 +29,6 @@ public static bool IsCSharp14OrAbove(this LanguageVersion languageVersion)
return languageVersion >= (LanguageVersion)1400;
}
- public static bool IsCSharp12OrAbove(this LanguageVersion languageVersion)
- {
- return languageVersion >= LanguageVersion.CSharp12;
- }
-
public static bool IsCSharp8OrAbove(this LanguageVersion languageVersion)
{
return languageVersion >= LanguageVersion.CSharp8;
diff --git a/src/Meziantou.Analyzer/Rules/BlazorPropertyInjectionShouldUseConstructorInjectionAnalyzer.cs b/src/Meziantou.Analyzer/Rules/BlazorPropertyInjectionShouldUseConstructorInjectionAnalyzer.cs
index 5bfa371e1..2ded39cfe 100644
--- a/src/Meziantou.Analyzer/Rules/BlazorPropertyInjectionShouldUseConstructorInjectionAnalyzer.cs
+++ b/src/Meziantou.Analyzer/Rules/BlazorPropertyInjectionShouldUseConstructorInjectionAnalyzer.cs
@@ -16,7 +16,7 @@ public sealed class BlazorPropertyInjectionShouldUseConstructorInjectionAnalyzer
messageFormat: "Use constructor injection instead of [Inject] attribute",
RuleCategories.Design,
DiagnosticSeverity.Info,
- isEnabledByDefault: true,
+ isEnabledByDefault: false,
description: "",
helpLinkUri: RuleIdentifiers.GetHelpUri(RuleIdentifiers.BlazorPropertyInjectionShouldUseConstructorInjection));
@@ -57,7 +57,7 @@ IComponentSymbol is not null &&
public void AnalyzeProperty(SymbolAnalysisContext context)
{
- if (context.Compilation.GetCSharpLanguageVersion() < LanguageVersion.CSharp12)
+ if (!context.Compilation.GetCSharpLanguageVersion().IsCSharp12OrAbove())
return;
var property = (IPropertySymbol)context.Symbol;
From 414314851b7a9adb62ca83fde3225532b63ac2b2 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Fri, 27 Feb 2026 04:31:02 +0000
Subject: [PATCH 4/5] Fix CI: wrap fixer files with #if CSHARP12_OR_GREATER for
Roslyn version compatibility
Co-authored-by: meziantou <509220+meziantou@users.noreply.github.com>
---
.../Rules/BlazorPropertyInjectionFixAllProvider.cs | 2 ++
...BlazorPropertyInjectionShouldUseConstructorInjectionFixer.cs | 2 ++
...opertyInjectionShouldUseConstructorInjectionAnalyzerTests.cs | 2 ++
3 files changed, 6 insertions(+)
diff --git a/src/Meziantou.Analyzer.CodeFixers/Rules/BlazorPropertyInjectionFixAllProvider.cs b/src/Meziantou.Analyzer.CodeFixers/Rules/BlazorPropertyInjectionFixAllProvider.cs
index f9e0a7641..48c2d7e57 100644
--- a/src/Meziantou.Analyzer.CodeFixers/Rules/BlazorPropertyInjectionFixAllProvider.cs
+++ b/src/Meziantou.Analyzer.CodeFixers/Rules/BlazorPropertyInjectionFixAllProvider.cs
@@ -1,3 +1,4 @@
+#if CSHARP12_OR_GREATER
using System.Collections.Immutable;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CodeActions;
@@ -61,3 +62,4 @@ private static async Task FixAllAsync(FixAllContext fixAllContext, Imm
return solution;
}
}
+#endif
diff --git a/src/Meziantou.Analyzer.CodeFixers/Rules/BlazorPropertyInjectionShouldUseConstructorInjectionFixer.cs b/src/Meziantou.Analyzer.CodeFixers/Rules/BlazorPropertyInjectionShouldUseConstructorInjectionFixer.cs
index e6d2114af..201a429d4 100644
--- a/src/Meziantou.Analyzer.CodeFixers/Rules/BlazorPropertyInjectionShouldUseConstructorInjectionFixer.cs
+++ b/src/Meziantou.Analyzer.CodeFixers/Rules/BlazorPropertyInjectionShouldUseConstructorInjectionFixer.cs
@@ -1,3 +1,4 @@
+#if CSHARP12_OR_GREATER
using System.Collections.Immutable;
using System.Composition;
using System.Text;
@@ -233,3 +234,4 @@ internal static string ComputeParameterName(string propertyName)
return sb.ToString();
}
}
+#endif
diff --git a/tests/Meziantou.Analyzer.Test/Rules/BlazorPropertyInjectionShouldUseConstructorInjectionAnalyzerTests.cs b/tests/Meziantou.Analyzer.Test/Rules/BlazorPropertyInjectionShouldUseConstructorInjectionAnalyzerTests.cs
index a6b07a2db..eb80c0d8c 100644
--- a/tests/Meziantou.Analyzer.Test/Rules/BlazorPropertyInjectionShouldUseConstructorInjectionAnalyzerTests.cs
+++ b/tests/Meziantou.Analyzer.Test/Rules/BlazorPropertyInjectionShouldUseConstructorInjectionAnalyzerTests.cs
@@ -1,3 +1,4 @@
+#if CSHARP12_OR_GREATER
using Meziantou.Analyzer.Rules;
using Meziantou.Analyzer.Test.Helpers;
using Microsoft.CodeAnalysis.CSharp;
@@ -254,3 +255,4 @@ private void HandleClick()
.ValidateAsync();
}
}
+#endif
From b5107669cb5cedca36b383e77f578b73bc7d1534 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Fri, 27 Feb 2026 04:40:01 +0000
Subject: [PATCH 5/5] Fix CI roslyn4.8: replace collection expression with
ImmutableArray.CreateRange
Co-authored-by: meziantou <509220+meziantou@users.noreply.github.com>
---
.../Rules/BlazorPropertyInjectionFixAllProvider.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/Meziantou.Analyzer.CodeFixers/Rules/BlazorPropertyInjectionFixAllProvider.cs b/src/Meziantou.Analyzer.CodeFixers/Rules/BlazorPropertyInjectionFixAllProvider.cs
index 48c2d7e57..b14439060 100644
--- a/src/Meziantou.Analyzer.CodeFixers/Rules/BlazorPropertyInjectionFixAllProvider.cs
+++ b/src/Meziantou.Analyzer.CodeFixers/Rules/BlazorPropertyInjectionFixAllProvider.cs
@@ -55,7 +55,7 @@ private static async Task FixAllAsync(FixAllContext fixAllContext, Imm
solution = await BlazorPropertyInjectionShouldUseConstructorInjectionFixer.FixDocumentAsync(
document,
- [.. documentDiagnostics],
+ ImmutableArray.CreateRange(documentDiagnostics),
cancellationToken).ConfigureAwait(false);
}