* 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,
|
||||
isEnabledByDefault: true,
|
||||
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>[]
|
||||
{
|
||||
UseMvcDiagnosticValidator.CreateAndInitialize,
|
||||
BuildServiceProviderValidator.CreateAndInitialize
|
||||
};
|
||||
|
||||
#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[]
|
||||
{
|
||||
UnsupportedUseMvcWithEndpointRouting,
|
||||
BuildServiceProviderShouldNotCalledInConfigureServicesMethod
|
||||
});
|
||||
|
||||
// By default the analyzer will only run for files ending with Startup.cs
|
||||
|
|
|
|||
|
|
@ -68,11 +68,11 @@ namespace Microsoft.AspNetCore.Analyzers
|
|||
Assert.Empty(diagnostics);
|
||||
|
||||
Assert.Collection(
|
||||
ConfigureServicesMethods.OrderBy(m => m.Name),
|
||||
ConfigureServicesMethods.OrderBy(m => m.Name),
|
||||
m => Assert.Equal("ConfigureServices", m.Name));
|
||||
|
||||
Assert.Collection(
|
||||
ConfigureMethods.OrderBy(m => m.Name),
|
||||
ConfigureMethods.OrderBy(m => m.Name),
|
||||
m => Assert.Equal("Configure", m.Name),
|
||||
m => Assert.Equal("ConfigureProduction", m.Name));
|
||||
}
|
||||
|
|
@ -209,7 +209,25 @@ namespace Microsoft.AspNetCore.Analyzers
|
|||
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)
|
||||
{
|
||||
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