* Resolve #11727 - Add a BuildServiceProviderValidator for checking startup method 'ConfigureServices(IServiceCollection,..)' * Fix file name and class name not match * Resolve conversation: - helpLink point to 'aka.ms' - Update DiagnosticDescriptor title - Update DiagnosticDescriptor messageFormat
This commit is contained in:
parent
99e99c167a
commit
d061d0d95b
|
|
@ -0,0 +1,41 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Linq;
|
||||||
|
using Microsoft.CodeAnalysis;
|
||||||
|
using Microsoft.CodeAnalysis.Diagnostics;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Analyzers
|
||||||
|
{
|
||||||
|
internal class BuildServiceProviderValidator : StartupDiagnosticValidator
|
||||||
|
{
|
||||||
|
public static BuildServiceProviderValidator CreateAndInitialize(CompilationAnalysisContext context, ConcurrentBag<StartupComputedAnalysis> analyses)
|
||||||
|
{
|
||||||
|
if (analyses == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(analyses));
|
||||||
|
}
|
||||||
|
|
||||||
|
var validator = new BuildServiceProviderValidator();
|
||||||
|
|
||||||
|
foreach (var serviceAnalysis in analyses.OfType<ServicesAnalysis>())
|
||||||
|
{
|
||||||
|
foreach (var serviceItem in serviceAnalysis.Services)
|
||||||
|
{
|
||||||
|
if (serviceItem.UseMethod.Name == "BuildServiceProvider")
|
||||||
|
{
|
||||||
|
context.ReportDiagnostic(Diagnostic.Create(
|
||||||
|
StartupAnalzyer.BuildServiceProviderShouldNotCalledInConfigureServicesMethod,
|
||||||
|
serviceItem.Operation.Syntax.GetLocation(),
|
||||||
|
serviceItem.UseMethod.Name,
|
||||||
|
serviceAnalysis.ConfigureServicesMethod.Name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return validator;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -16,5 +16,15 @@ namespace Microsoft.AspNetCore.Analyzers
|
||||||
DiagnosticSeverity.Warning,
|
DiagnosticSeverity.Warning,
|
||||||
isEnabledByDefault: true,
|
isEnabledByDefault: true,
|
||||||
helpLinkUri: "https://aka.ms/YJggeFn");
|
helpLinkUri: "https://aka.ms/YJggeFn");
|
||||||
|
|
||||||
|
internal readonly static DiagnosticDescriptor BuildServiceProviderShouldNotCalledInConfigureServicesMethod = new DiagnosticDescriptor(
|
||||||
|
"MVC1007",
|
||||||
|
"Do not call 'IServiceCollection.BuildServiceProvider' in 'ConfigureServices'",
|
||||||
|
"Calling 'BuildServiceProvider' from application code results in an additional copy of singleton services being created. Consider alternatives such as dependency injecting services as parameters to 'Configure'.",
|
||||||
|
"Design",
|
||||||
|
DiagnosticSeverity.Warning,
|
||||||
|
isEnabledByDefault: true,
|
||||||
|
helpLinkUri: "https://aka.ms/AA5k895"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ namespace Microsoft.AspNetCore.Analyzers
|
||||||
private readonly static Func<CompilationAnalysisContext, ConcurrentBag<StartupComputedAnalysis>, StartupDiagnosticValidator>[] DiagnosticValidatorFactories = new Func<CompilationAnalysisContext, ConcurrentBag<StartupComputedAnalysis>, StartupDiagnosticValidator>[]
|
private readonly static Func<CompilationAnalysisContext, ConcurrentBag<StartupComputedAnalysis>, StartupDiagnosticValidator>[] DiagnosticValidatorFactories = new Func<CompilationAnalysisContext, ConcurrentBag<StartupComputedAnalysis>, StartupDiagnosticValidator>[]
|
||||||
{
|
{
|
||||||
UseMvcDiagnosticValidator.CreateAndInitialize,
|
UseMvcDiagnosticValidator.CreateAndInitialize,
|
||||||
|
BuildServiceProviderValidator.CreateAndInitialize
|
||||||
};
|
};
|
||||||
|
|
||||||
#pragma warning restore RS1008 // Avoid storing per-compilation data into the fields of a diagnostic analyzer.
|
#pragma warning restore RS1008 // Avoid storing per-compilation data into the fields of a diagnostic analyzer.
|
||||||
|
|
@ -36,6 +37,7 @@ namespace Microsoft.AspNetCore.Analyzers
|
||||||
SupportedDiagnostics = ImmutableArray.Create<DiagnosticDescriptor>(new[]
|
SupportedDiagnostics = ImmutableArray.Create<DiagnosticDescriptor>(new[]
|
||||||
{
|
{
|
||||||
UnsupportedUseMvcWithEndpointRouting,
|
UnsupportedUseMvcWithEndpointRouting,
|
||||||
|
BuildServiceProviderShouldNotCalledInConfigureServicesMethod
|
||||||
});
|
});
|
||||||
|
|
||||||
// By default the analyzer will only run for files ending with Startup.cs
|
// By default the analyzer will only run for files ending with Startup.cs
|
||||||
|
|
|
||||||
|
|
@ -209,7 +209,25 @@ namespace Microsoft.AspNetCore.Analyzers
|
||||||
AnalyzerAssert.DiagnosticLocation(source.MarkerLocations["MM3"], diagnostic.Location);
|
AnalyzerAssert.DiagnosticLocation(source.MarkerLocations["MM3"], diagnostic.Location);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
[Fact]
|
||||||
|
public async Task StartupAnalyzer_ServicesAnalysis_CallBuildServiceProvider()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var source = ReadSource("ConfigureServices_BuildServiceProvider");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var diagnostics = await Runner.GetDiagnosticsAsync(source.Source);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
var servicesAnalysis = Assert.Single(Analyses.OfType<ServicesAnalysis>());
|
||||||
|
Assert.NotEmpty(servicesAnalysis.Services);
|
||||||
|
Assert.Collection(diagnostics,
|
||||||
|
diagnostic =>
|
||||||
|
{
|
||||||
|
Assert.Same(StartupAnalzyer.BuildServiceProviderShouldNotCalledInConfigureServicesMethod, diagnostic.Descriptor);
|
||||||
|
AnalyzerAssert.DiagnosticLocation(source.MarkerLocations["MM1"], diagnostic.Location);
|
||||||
|
});
|
||||||
|
}
|
||||||
private TestSource ReadSource(string fileName)
|
private TestSource ReadSource(string fileName)
|
||||||
{
|
{
|
||||||
return MvcTestSource.Read(nameof(StartupAnalyzerTest), fileName);
|
return MvcTestSource.Read(nameof(StartupAnalyzerTest), fileName);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using Microsoft.AspNetCore.Builder;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Analyzers.TestFiles.StartupAnalyzerTest
|
||||||
|
{
|
||||||
|
public class ConfigureServices_BuildServiceProvider
|
||||||
|
{
|
||||||
|
public void ConfigureServices(IServiceCollection services)
|
||||||
|
{
|
||||||
|
/*MM1*/services.BuildServiceProvider();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Configure(IApplicationBuilder app)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue