diff --git a/src/Framework/AspNetCoreAnalyzers/src/Analyzers/DiagnosticDescriptors.cs b/src/Framework/AspNetCoreAnalyzers/src/Analyzers/DiagnosticDescriptors.cs index a2d5903de4e3dd5b27e2c40cc2b607959057eab4..12505fe547444783a3940a4fe852f211aef3705d 100644 --- a/src/Framework/AspNetCoreAnalyzers/src/Analyzers/DiagnosticDescriptors.cs +++ b/src/Framework/AspNetCoreAnalyzers/src/Analyzers/DiagnosticDescriptors.cs @@ -88,4 +88,13 @@ internal static class DiagnosticDescriptors DiagnosticSeverity.Warning, isEnabledByDefault: true, helpLinkUri: "https://aka.ms/aspnet/analyzers"); + + internal static readonly DiagnosticDescriptor DisallowConfigureAppConfigureHostBuilder = new( + "ASP0013", + "Suggest using WebApplicationBuilder.Configuration over Configure methods", + "Suggest using WebApplicationBuilder.Configuration instead of {0}", + "Usage", + DiagnosticSeverity.Warning, + isEnabledByDefault: true, + helpLinkUri: "https://aka.ms/aspnet/analyzers"); } diff --git a/src/Framework/AspNetCoreAnalyzers/src/Analyzers/WebApplicationBuilder/WebApplicationBuilderAnalyzer.cs b/src/Framework/AspNetCoreAnalyzers/src/Analyzers/WebApplicationBuilder/WebApplicationBuilderAnalyzer.cs index 0e1b4f220e4a36220972e98816db954c57676718..a538dbc22ae682a6ab4be131524b7f5271ad3a87 100644 --- a/src/Framework/AspNetCoreAnalyzers/src/Analyzers/WebApplicationBuilder/WebApplicationBuilderAnalyzer.cs +++ b/src/Framework/AspNetCoreAnalyzers/src/Analyzers/WebApplicationBuilder/WebApplicationBuilderAnalyzer.cs @@ -21,7 +21,8 @@ public class WebApplicationBuilderAnalyzer : DiagnosticAnalyzer DiagnosticDescriptors.DoNotUseConfigureWebHostWithConfigureHostBuilder, DiagnosticDescriptors.DoNotUseConfigureWithConfigureWebHostBuilder, DiagnosticDescriptors.DoNotUseUseStartupWithConfigureWebHostBuilder, - DiagnosticDescriptors.DoNotUseHostConfigureLogging + DiagnosticDescriptors.DoNotUseHostConfigureLogging, + DiagnosticDescriptors.DisallowConfigureAppConfigureHostBuilder }); public override void Initialize(AnalysisContext context) @@ -50,6 +51,14 @@ public class WebApplicationBuilderAnalyzer : DiagnosticAnalyzer wellKnownTypes.HostingHostBuilderExtensions, wellKnownTypes.WebHostBuilderExtensions }; + INamedTypeSymbol[] configureAppTypes = + { + wellKnownTypes.ConfigureHostBuilder, + wellKnownTypes.ConfigureWebHostBuilder, + wellKnownTypes.WebHostBuilderExtensions, + wellKnownTypes.HostingHostBuilderExtensions, + }; + INamedTypeSymbol[] configureHostTypes = { wellKnownTypes.ConfigureHostBuilder }; compilationStartAnalysisContext.RegisterOperationAction(operationAnalysisContext => { @@ -103,7 +112,7 @@ public class WebApplicationBuilderAnalyzer : DiagnosticAnalyzer DiagnosticDescriptors.DoNotUseUseStartupWithConfigureWebHostBuilder, invocation)); } - + //var builder = WebApplication.CreateBuilder(args); //builder.Host.ConfigureLogging(x => {}) if (IsDisallowedMethod( @@ -135,6 +144,54 @@ public class WebApplicationBuilderAnalyzer : DiagnosticAnalyzer DiagnosticDescriptors.DoNotUseHostConfigureLogging, invocation)); } + + // var builder = WebApplication.CreateBuilder(); + // builder.WebHost.ConfigureAppConfiguration(builder => {}); + if (IsDisallowedMethod( + operationAnalysisContext, + invocation, + targetMethod, + wellKnownTypes.ConfigureWebHostBuilder, + "ConfigureAppConfiguration", + configureAppTypes)) + { + operationAnalysisContext.ReportDiagnostic( + CreateDiagnostic( + DiagnosticDescriptors.DisallowConfigureAppConfigureHostBuilder, + invocation)); + } + + // var builder = WebApplication.CreateBuilder(); + // builder.Host.ConfigureAppConfiguration(builder => {}); + if (IsDisallowedMethod( + operationAnalysisContext, + invocation, + targetMethod, + wellKnownTypes.ConfigureHostBuilder, + "ConfigureAppConfiguration", + configureAppTypes)) + { + operationAnalysisContext.ReportDiagnostic( + CreateDiagnostic( + DiagnosticDescriptors.DisallowConfigureAppConfigureHostBuilder, + invocation)); + } + + // var builder = WebApplication.CreateBuilder(); + // builder.Host.ConfigureHostConfiguration(builder => {}); + if (IsDisallowedMethod( + operationAnalysisContext, + invocation, + targetMethod, + wellKnownTypes.ConfigureHostBuilder, + "ConfigureHostConfiguration", + configureHostTypes)) + { + operationAnalysisContext.ReportDiagnostic( + CreateDiagnostic( + DiagnosticDescriptors.DisallowConfigureAppConfigureHostBuilder, + invocation)); + } static Diagnostic CreateDiagnostic(DiagnosticDescriptor descriptor, IInvocationOperation operation) { diff --git a/src/Framework/AspNetCoreAnalyzers/test/WebApplicationBuilder/DisallowConfigureAppConfigureHostBuilderTest.cs b/src/Framework/AspNetCoreAnalyzers/test/WebApplicationBuilder/DisallowConfigureAppConfigureHostBuilderTest.cs new file mode 100644 index 0000000000000000000000000000000000000000..96e61c63154c21efcbaf90a27c6e47e7c4dd6a44 --- /dev/null +++ b/src/Framework/AspNetCoreAnalyzers/test/WebApplicationBuilder/DisallowConfigureAppConfigureHostBuilderTest.cs @@ -0,0 +1,210 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Globalization; +using Microsoft.AspNetCore.Analyzer.Testing; + +namespace Microsoft.AspNetCore.Analyzers.WebApplicationBuilder; +public partial class DisallowConfigureAppConfigureHostBuilderTest +{ + private TestDiagnosticAnalyzerRunner Runner { get; } = new(new WebApplicationBuilderAnalyzer()); + + [Fact] + public async Task ConfigurationBuilderRunsWithoutDiagnostic() + { + // Arrange + var source = @" +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.Configuration; +var builder = WebApplication.CreateBuilder(args); +builder.Configuration.AddJsonFile(""foo.json"", optional: true); +"; + // Act + var diagnostic = await Runner.GetDiagnosticsAsync(source); + + // Assert + Assert.Empty(diagnostic); + } + + [Fact] + public async Task ConfigureAppHostBuilderProducesDiagnostic() + { + // Arrange + var source = TestSource.Read(@" +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Configuration; +var builder = WebApplication.CreateBuilder(args); +builder.Host./*MM*/ConfigureAppConfiguration(builder => +{ + builder.AddJsonFile(""foo.json"", optional: true); +}); +"); + + // Act + var diagnostics = await Runner.GetDiagnosticsAsync(source.Source); + + // Assert + var diagnostic = Assert.Single(diagnostics); + Assert.Same(DiagnosticDescriptors.DisallowConfigureAppConfigureHostBuilder, diagnostic.Descriptor); + AnalyzerAssert.DiagnosticLocation(source.DefaultMarkerLocation, diagnostic.Location); + Assert.Equal("Suggest using WebApplicationBuilder.Configuration instead of ConfigureAppConfiguration", diagnostic.GetMessage(CultureInfo.InvariantCulture)); + } + + [Fact] + public async Task ConfigureHostHostBuilderProducesDiagnostic() + { + // Arrange + var source = TestSource.Read(@" +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.Configuration; +var builder = WebApplication.CreateBuilder(args); +builder.Host./*MM*/ConfigureHostConfiguration(builder => +{ + builder.AddJsonFile(""foo.json"", optional: true); +}); +"); + + // Act + var diagnostics = await Runner.GetDiagnosticsAsync(source.Source); + + // Assert + var diagnostic = Assert.Single(diagnostics); + Assert.Same(DiagnosticDescriptors.DisallowConfigureAppConfigureHostBuilder, diagnostic.Descriptor); + AnalyzerAssert.DiagnosticLocation(source.DefaultMarkerLocation, diagnostic.Location); + Assert.Equal("Suggest using WebApplicationBuilder.Configuration instead of ConfigureHostConfiguration", diagnostic.GetMessage(CultureInfo.InvariantCulture)); + } + + [Fact] + public async Task ConfigureAppWebHostBuilderProducesDiagnostic() + { + // Arrange + var source = TestSource.Read(@" +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; +var builder = WebApplication.CreateBuilder(args); +builder.WebHost./*MM*/ConfigureAppConfiguration(builder => +{ + builder.AddJsonFile(""foo.json"", optional: true); +}); +"); + + // Act + var diagnostics = await Runner.GetDiagnosticsAsync(source.Source); + + // Assert + var diagnostic = Assert.Single(diagnostics); + Assert.Same(DiagnosticDescriptors.DisallowConfigureAppConfigureHostBuilder, diagnostic.Descriptor); + AnalyzerAssert.DiagnosticLocation(source.DefaultMarkerLocation, diagnostic.Location); + Assert.Equal("Suggest using WebApplicationBuilder.Configuration instead of ConfigureAppConfiguration", diagnostic.GetMessage(CultureInfo.InvariantCulture)); + } + + [Fact] + public async Task ConfigureAppWebHostBuilderWithContextProducesDiagnostic() + { + // Arrange + var source = TestSource.Read(@" +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; +var builder = WebApplication.CreateBuilder(args); +builder.WebHost./*MM*/ConfigureAppConfiguration((context, webHostBuilder) => { }); +"); + + // Act + var diagnostics = await Runner.GetDiagnosticsAsync(source.Source); + + // Assert + var diagnostic = Assert.Single(diagnostics); + Assert.Same(DiagnosticDescriptors.DisallowConfigureAppConfigureHostBuilder, diagnostic.Descriptor); + AnalyzerAssert.DiagnosticLocation(source.DefaultMarkerLocation, diagnostic.Location); + Assert.Equal("Suggest using WebApplicationBuilder.Configuration instead of ConfigureAppConfiguration", diagnostic.GetMessage(CultureInfo.InvariantCulture)); + } + [Fact] + public async Task ConfigureAppWebHostBuilderProducesDiagnosticInMain() + { + // Arrange + var source = TestSource.Read(@" +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; +public static class Test +{ + public static void Main(string[]args) { + var builder = WebApplication.CreateBuilder(args); + builder.WebHost./*MM*/ConfigureAppConfiguration(builder => { }); +} +} +"); + + // Act + var diagnostics = await Runner.GetDiagnosticsAsync(source.Source); + + // Assert + var diagnostic = Assert.Single(diagnostics); + Assert.Same(DiagnosticDescriptors.DisallowConfigureAppConfigureHostBuilder, diagnostic.Descriptor); + AnalyzerAssert.DiagnosticLocation(source.DefaultMarkerLocation, diagnostic.Location); + Assert.Equal("Suggest using WebApplicationBuilder.Configuration instead of ConfigureAppConfiguration", diagnostic.GetMessage(CultureInfo.InvariantCulture)); + } + [Fact] + public async Task ConfigureAppWebHostOnBuilderProducesDiagnosticInMain() + { + // Arrange + var source = TestSource.Read(@" +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; +public static class Test +{ + public static void Main(string[]args) { + var builder = WebApplication.CreateBuilder(args); + var webhost = builder.WebHost; + webhost./*MM*/ConfigureAppConfiguration(builder => { }); +} +} +"); + + // Act + var diagnostics = await Runner.GetDiagnosticsAsync(source.Source); + + // Assert + var diagnostic = Assert.Single(diagnostics); + Assert.Same(DiagnosticDescriptors.DisallowConfigureAppConfigureHostBuilder, diagnostic.Descriptor); + AnalyzerAssert.DiagnosticLocation(source.DefaultMarkerLocation, diagnostic.Location); + Assert.Equal("Suggest using WebApplicationBuilder.Configuration instead of ConfigureAppConfiguration", diagnostic.GetMessage(CultureInfo.InvariantCulture)); + } + [Fact] + public async Task TwoInvocationsProduceTwoDiagnostic() + { + // Arrange + var source = TestSource.Read(@" +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; +var builder = WebApplication.CreateBuilder(args); +builder.Host./*MM1*/ConfigureHostConfiguration(builder => +{ + builder.AddJsonFile(""foo.json"", optional: true); +}); +builder.WebHost./*MM2*/ConfigureAppConfiguration(builder => +{ + builder.AddJsonFile(""foo.json"", optional: true); +}); +"); + + // Act + var diagnostics = await Runner.GetDiagnosticsAsync(source.Source); + + // Assert + Assert.Equal(2, diagnostics.Length); + var diagnostic1 = diagnostics[0]; + var diagnostic2 = diagnostics[1]; + Assert.Same(DiagnosticDescriptors.DisallowConfigureAppConfigureHostBuilder, diagnostic1.Descriptor); + AnalyzerAssert.DiagnosticLocation(source.MarkerLocations["MM1"], diagnostic1.Location); + Assert.Equal("Suggest using WebApplicationBuilder.Configuration instead of ConfigureHostConfiguration", diagnostic1.GetMessage(CultureInfo.InvariantCulture)); + Assert.Same(DiagnosticDescriptors.DisallowConfigureAppConfigureHostBuilder, diagnostic2.Descriptor); + AnalyzerAssert.DiagnosticLocation(source.MarkerLocations["MM2"], diagnostic2.Location); + Assert.Equal("Suggest using WebApplicationBuilder.Configuration instead of ConfigureAppConfiguration", diagnostic2.GetMessage(CultureInfo.InvariantCulture)); + } +} diff --git a/src/Http/samples/MinimalSample/Program.cs b/src/Http/samples/MinimalSample/Program.cs index d0930830de153128ad12fa2ab4c0cbe4ebd5ef96..41914ad574d0a2e763695e53c3f8dadb15711365 100644 --- a/src/Http/samples/MinimalSample/Program.cs +++ b/src/Http/samples/MinimalSample/Program.cs @@ -18,7 +18,6 @@ app.MapGet("/", () => $""" Username: {Environment.UserName} Date and Time: {DateTime.Now} """); - var outer = app.MapGroup("/outer"); var inner = outer.MapGroup("/inner");