Add StartupAnalzyer (#9100)
This commit is contained in:
parent
4ac9001f6e
commit
69f4b6d227
|
|
@ -52,5 +52,8 @@ namespace Microsoft.AspNetCore.Mvc.Analyzers
|
|||
DiagnosticSeverity.Warning,
|
||||
isEnabledByDefault: true,
|
||||
helpLinkUri: "https://aka.ms/AA20pbc");
|
||||
|
||||
|
||||
// MVC1005 reserved for startup
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
// 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.CodeAnalysis;
|
||||
|
||||
namespace Microsoft.AspNetCore.Analyzers
|
||||
{
|
||||
internal abstract class ConfigureMethodAnalysis : StartupComputedAnalysis
|
||||
{
|
||||
protected ConfigureMethodAnalysis(IMethodSymbol configureMethod)
|
||||
: base(configureMethod.ContainingType)
|
||||
{
|
||||
ConfigureMethod = configureMethod;
|
||||
}
|
||||
|
||||
public IMethodSymbol ConfigureMethod { get; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
// 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.CodeAnalysis;
|
||||
|
||||
namespace Microsoft.AspNetCore.Analyzers
|
||||
{
|
||||
internal abstract class ConfigureServicesMethodAnalysis : StartupComputedAnalysis
|
||||
{
|
||||
protected ConfigureServicesMethodAnalysis(IMethodSymbol configureServicesMethod)
|
||||
: base(configureServicesMethod.ContainingType)
|
||||
{
|
||||
ConfigureServicesMethod = configureServicesMethod;
|
||||
}
|
||||
|
||||
public IMethodSymbol ConfigureServicesMethod { get; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
// 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.Immutable;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.Operations;
|
||||
|
||||
namespace Microsoft.AspNetCore.Analyzers
|
||||
{
|
||||
internal class MiddlewareAnalysis : ConfigureMethodAnalysis
|
||||
{
|
||||
public static MiddlewareAnalysis CreateAndInitialize(StartupAnalysisContext context)
|
||||
{
|
||||
if (context == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(context));
|
||||
}
|
||||
|
||||
var symbols = context.StartupSymbols;
|
||||
var analysis = new MiddlewareAnalysis((IMethodSymbol)context.OperationBlockStartAnalysisContext.OwningSymbol);
|
||||
|
||||
var middleware = ImmutableArray.CreateBuilder<MiddlewareItem>();
|
||||
|
||||
context.OperationBlockStartAnalysisContext.RegisterOperationAction(context =>
|
||||
{
|
||||
// We're looking for usage of extension methods, so we need to look at the 'this' parameter
|
||||
// rather than invocation.Instance.
|
||||
if (context.Operation is IInvocationOperation invocation &&
|
||||
invocation.Instance == null &&
|
||||
invocation.Arguments.Length >= 1 &&
|
||||
invocation.Arguments[0].Parameter?.Type == symbols.IApplicationBuilder)
|
||||
{
|
||||
middleware.Add(new MiddlewareItem(invocation));
|
||||
}
|
||||
}, OperationKind.Invocation);
|
||||
|
||||
context.OperationBlockStartAnalysisContext.RegisterOperationBlockEndAction(context =>
|
||||
{
|
||||
analysis.Middleware = middleware.ToImmutable();
|
||||
});
|
||||
|
||||
return analysis;
|
||||
}
|
||||
|
||||
public MiddlewareAnalysis(IMethodSymbol configureMethod)
|
||||
: base(configureMethod)
|
||||
{
|
||||
}
|
||||
|
||||
public ImmutableArray<MiddlewareItem> Middleware { get; private set; } = ImmutableArray<MiddlewareItem>.Empty;
|
||||
}
|
||||
}
|
||||
|
|
@ -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.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.Operations;
|
||||
|
||||
namespace Microsoft.AspNetCore.Analyzers
|
||||
{
|
||||
internal class MiddlewareItem
|
||||
{
|
||||
public MiddlewareItem(IInvocationOperation operation)
|
||||
{
|
||||
Operation = operation;
|
||||
}
|
||||
|
||||
public IInvocationOperation Operation { get; }
|
||||
|
||||
public IMethodSymbol UseMethod => Operation.TargetMethod;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
// 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 Microsoft.AspNetCore.Mvc.Analyzers;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.Diagnostics;
|
||||
using Microsoft.CodeAnalysis.Operations;
|
||||
|
||||
namespace Microsoft.AspNetCore.Analyzers
|
||||
{
|
||||
internal class MvcOptionsAnalysis : ConfigureServicesMethodAnalysis
|
||||
{
|
||||
public static MvcOptionsAnalysis CreateAndInitialize(StartupAnalysisContext context)
|
||||
{
|
||||
if (context == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(context));
|
||||
}
|
||||
|
||||
var analysis = new MvcOptionsAnalysis((IMethodSymbol)context.OperationBlockStartAnalysisContext.OwningSymbol);
|
||||
|
||||
context.OperationBlockStartAnalysisContext.RegisterOperationAction(context =>
|
||||
{
|
||||
if (context.Operation is ISimpleAssignmentOperation operation &&
|
||||
operation.Value.ConstantValue.HasValue &&
|
||||
operation.Target is IPropertyReferenceOperation property &&
|
||||
property.Member?.Name == SymbolNames.EnableEndpointRoutingProperty)
|
||||
{
|
||||
analysis.EndpointRoutingEnabled = operation.Value.ConstantValue.Value as bool?;
|
||||
}
|
||||
|
||||
}, OperationKind.SimpleAssignment);
|
||||
|
||||
return analysis;
|
||||
}
|
||||
|
||||
public MvcOptionsAnalysis(IMethodSymbol configureServicesMethod)
|
||||
: base(configureServicesMethod)
|
||||
{
|
||||
}
|
||||
|
||||
public bool? EndpointRoutingEnabled { get; private set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
// 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.Immutable;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.Operations;
|
||||
|
||||
namespace Microsoft.AspNetCore.Analyzers
|
||||
{
|
||||
internal class ServicesAnalysis : ConfigureServicesMethodAnalysis
|
||||
{
|
||||
public static ServicesAnalysis CreateAndInitialize(StartupAnalysisContext context)
|
||||
{
|
||||
if (context == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(context));
|
||||
}
|
||||
|
||||
var symbols = context.StartupSymbols;
|
||||
var analysis = new ServicesAnalysis((IMethodSymbol)context.OperationBlockStartAnalysisContext.OwningSymbol);
|
||||
|
||||
var services = ImmutableArray.CreateBuilder<ServicesItem>();
|
||||
context.OperationBlockStartAnalysisContext.RegisterOperationAction(context =>
|
||||
{
|
||||
// We're looking for usage of extension methods, so we need to look at the 'this' parameter
|
||||
// rather than invocation.Instance.
|
||||
if (context.Operation is IInvocationOperation invocation &&
|
||||
invocation.Instance == null &&
|
||||
invocation.Arguments.Length >= 1 &&
|
||||
invocation.Arguments[0].Parameter?.Type == symbols.IServiceCollection)
|
||||
{
|
||||
services.Add(new ServicesItem(invocation));
|
||||
}
|
||||
}, OperationKind.Invocation);
|
||||
|
||||
context.OperationBlockStartAnalysisContext.RegisterOperationBlockEndAction(context =>
|
||||
{
|
||||
analysis.Services = services.ToImmutable();
|
||||
});
|
||||
|
||||
return analysis;
|
||||
}
|
||||
|
||||
public ServicesAnalysis(IMethodSymbol configureServicesMethod)
|
||||
: base(configureServicesMethod)
|
||||
{
|
||||
}
|
||||
|
||||
public ImmutableArray<ServicesItem> Services { get; private set; } = ImmutableArray<ServicesItem>.Empty;
|
||||
}
|
||||
}
|
||||
|
|
@ -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.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.Operations;
|
||||
|
||||
namespace Microsoft.AspNetCore.Analyzers
|
||||
{
|
||||
internal class ServicesItem
|
||||
{
|
||||
public ServicesItem(IInvocationOperation operation)
|
||||
{
|
||||
Operation = operation;
|
||||
}
|
||||
|
||||
public IInvocationOperation Operation { get; }
|
||||
|
||||
public IMethodSymbol UseMethod => Operation.TargetMethod;
|
||||
}
|
||||
}
|
||||
|
|
@ -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.CodeAnalysis.Diagnostics;
|
||||
|
||||
namespace Microsoft.AspNetCore.Analyzers
|
||||
{
|
||||
internal class StartupAnalysisContext
|
||||
{
|
||||
public StartupAnalysisContext(OperationBlockStartAnalysisContext operationBlockStartAnalysisContext, StartupSymbols startupSymbols)
|
||||
{
|
||||
OperationBlockStartAnalysisContext = operationBlockStartAnalysisContext;
|
||||
StartupSymbols = startupSymbols;
|
||||
}
|
||||
|
||||
public OperationBlockStartAnalysisContext OperationBlockStartAnalysisContext { get; }
|
||||
|
||||
public StartupSymbols StartupSymbols { get; }
|
||||
}
|
||||
}
|
||||
|
|
@ -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.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.Diagnostics;
|
||||
|
||||
namespace Microsoft.AspNetCore.Analyzers
|
||||
{
|
||||
public partial class StartupAnalzyer : DiagnosticAnalyzer
|
||||
{
|
||||
internal readonly static DiagnosticDescriptor UnsupportedUseMvcWithEndpointRouting = new DiagnosticDescriptor(
|
||||
"MVC1005",
|
||||
"Cannot use UseMvc with Endpoint Routing.",
|
||||
"Using '{0}' to configure MVC is not supported while using Endpoint Routing. To continue using '{0}', please set 'MvcOptions.EnableEndpointRounting = false' inside '{1}'.",
|
||||
"Usage",
|
||||
DiagnosticSeverity.Warning,
|
||||
isEnabledByDefault: true,
|
||||
helpLinkUri: "https://aka.ms/YJggeFn");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
// 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 Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.Diagnostics;
|
||||
|
||||
namespace Microsoft.AspNetCore.Analyzers
|
||||
{
|
||||
public partial class StartupAnalzyer : DiagnosticAnalyzer
|
||||
{
|
||||
internal event EventHandler<StartupComputedAnalysis> AnalysisStarted;
|
||||
|
||||
private void OnAnalysisStarted(StartupComputedAnalysis analysis)
|
||||
{
|
||||
AnalysisStarted?.Invoke(this, analysis);
|
||||
}
|
||||
|
||||
internal event EventHandler<IMethodSymbol> ConfigureServicesMethodFound;
|
||||
|
||||
private void OnConfigureServicesMethodFound(IMethodSymbol method)
|
||||
{
|
||||
ConfigureServicesMethodFound?.Invoke(this, method);
|
||||
}
|
||||
|
||||
internal event EventHandler<IMethodSymbol> ConfigureMethodFound;
|
||||
|
||||
private void OnConfigureMethodFound(IMethodSymbol method)
|
||||
{
|
||||
ConfigureMethodFound?.Invoke(this, method);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,148 @@
|
|||
// 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.Collections.Immutable;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.Diagnostics;
|
||||
|
||||
namespace Microsoft.AspNetCore.Analyzers
|
||||
{
|
||||
[DiagnosticAnalyzer(LanguageNames.CSharp)]
|
||||
public partial class StartupAnalzyer : DiagnosticAnalyzer
|
||||
{
|
||||
#pragma warning disable RS1008 // Avoid storing per-compilation data into the fields of a diagnostic analyzer.
|
||||
private readonly static Func<StartupAnalysisContext, StartupComputedAnalysis>[] ConfigureServicesMethodAnalysisFactories = new Func<StartupAnalysisContext, StartupComputedAnalysis>[]
|
||||
{
|
||||
ServicesAnalysis.CreateAndInitialize,
|
||||
MvcOptionsAnalysis.CreateAndInitialize,
|
||||
};
|
||||
|
||||
private readonly static Func<StartupAnalysisContext, StartupComputedAnalysis>[] ConfigureMethodAnalysisFactories = new Func<StartupAnalysisContext, StartupComputedAnalysis>[]
|
||||
{
|
||||
MiddlewareAnalysis.CreateAndInitialize,
|
||||
};
|
||||
|
||||
private readonly static Func<CompilationAnalysisContext, ConcurrentBag<StartupComputedAnalysis>, StartupDiagnosticValidator>[] DiagnosticValidatorFactories = new Func<CompilationAnalysisContext, ConcurrentBag<StartupComputedAnalysis>, StartupDiagnosticValidator>[]
|
||||
{
|
||||
UseMvcDiagnosticValidator.CreateAndInitialize,
|
||||
};
|
||||
|
||||
#pragma warning restore RS1008 // Avoid storing per-compilation data into the fields of a diagnostic analyzer.
|
||||
|
||||
public StartupAnalzyer()
|
||||
{
|
||||
SupportedDiagnostics = ImmutableArray.Create<DiagnosticDescriptor>(new[]
|
||||
{
|
||||
UnsupportedUseMvcWithEndpointRouting,
|
||||
});
|
||||
|
||||
// By default the analyzer will only run for files ending with Startup.cs
|
||||
// Can be overriden for unit testing other file names
|
||||
// Analzyer only runs for C# so limiting to *.cs file is fine
|
||||
StartupFilePredicate = path => path.EndsWith("Startup.cs", StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
internal Func<string, bool> StartupFilePredicate { get; set; }
|
||||
|
||||
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get; }
|
||||
|
||||
public override void Initialize(AnalysisContext context)
|
||||
{
|
||||
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
|
||||
context.RegisterCompilationStartAction(OnCompilationStart);
|
||||
}
|
||||
|
||||
private void OnCompilationStart(CompilationStartAnalysisContext context)
|
||||
{
|
||||
var symbols = new StartupSymbols(context.Compilation);
|
||||
|
||||
// Don't run analyzer if ASP.NET Core types cannot be found
|
||||
if (symbols.IServiceCollection == null || symbols.IApplicationBuilder == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// This analyzer is a general-purpose framework that functions by:
|
||||
// 1. Discovering Startup methods (ConfigureServices, Configure)
|
||||
// 2. Launching additional analyses of these Startup methods and collecting results
|
||||
// 3. Running a final pass to add diagnostics based on computed state
|
||||
var analyses = new ConcurrentBag<StartupComputedAnalysis>();
|
||||
|
||||
context.RegisterOperationBlockStartAction(context =>
|
||||
{
|
||||
AnalyzeStartupMethods(context, symbols, analyses);
|
||||
});
|
||||
|
||||
// Run after analyses have had a chance to finish to add diagnostics.
|
||||
context.RegisterCompilationEndAction(analysisContext =>
|
||||
{
|
||||
RunAnalysis(analysisContext, analyses);
|
||||
});
|
||||
}
|
||||
|
||||
private static void RunAnalysis(CompilationAnalysisContext analysisContext, ConcurrentBag<StartupComputedAnalysis> analyses)
|
||||
{
|
||||
for (var i = 0; i < DiagnosticValidatorFactories.Length; i++)
|
||||
{
|
||||
var validator = DiagnosticValidatorFactories[i].Invoke(analysisContext, analyses);
|
||||
}
|
||||
}
|
||||
|
||||
private void AnalyzeStartupMethods(OperationBlockStartAnalysisContext context, StartupSymbols symbols, ConcurrentBag<StartupComputedAnalysis> analyses)
|
||||
{
|
||||
if (!IsStartupFile(context))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (context.OwningSymbol.Kind != SymbolKind.Method)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var startupAnalysisContext = new StartupAnalysisContext(context, symbols);
|
||||
|
||||
var method = (IMethodSymbol)context.OwningSymbol;
|
||||
if (StartupFacts.IsConfigureServices(symbols, method))
|
||||
{
|
||||
for (var i = 0; i < ConfigureServicesMethodAnalysisFactories.Length; i++)
|
||||
{
|
||||
var analysis = ConfigureServicesMethodAnalysisFactories[i].Invoke(startupAnalysisContext);
|
||||
analyses.Add(analysis);
|
||||
|
||||
OnAnalysisStarted(analysis);
|
||||
}
|
||||
|
||||
OnConfigureServicesMethodFound(method);
|
||||
}
|
||||
|
||||
if (StartupFacts.IsConfigure(symbols, method))
|
||||
{
|
||||
for (var i = 0; i < ConfigureMethodAnalysisFactories.Length; i++)
|
||||
{
|
||||
var analysis = ConfigureMethodAnalysisFactories[i].Invoke(startupAnalysisContext);
|
||||
analyses.Add(analysis);
|
||||
|
||||
OnAnalysisStarted(analysis);
|
||||
}
|
||||
|
||||
OnConfigureMethodFound(method);
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsStartupFile(OperationBlockStartAnalysisContext context)
|
||||
{
|
||||
foreach (var location in context.OwningSymbol.Locations)
|
||||
{
|
||||
if (location.IsInSource && StartupFilePredicate(location.SourceTree.FilePath))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
// 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.CodeAnalysis;
|
||||
|
||||
namespace Microsoft.AspNetCore.Analyzers
|
||||
{
|
||||
internal abstract class StartupComputedAnalysis
|
||||
{
|
||||
protected StartupComputedAnalysis(INamedTypeSymbol enclosingType)
|
||||
{
|
||||
EnclosingType = enclosingType;
|
||||
}
|
||||
|
||||
public INamedTypeSymbol EnclosingType { get; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
// 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.
|
||||
|
||||
namespace Microsoft.AspNetCore.Analyzers
|
||||
{
|
||||
internal abstract class StartupDiagnosticValidator
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
// 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 Microsoft.AspNetCore.Mvc.Analyzers;
|
||||
using Microsoft.CodeAnalysis;
|
||||
|
||||
namespace Microsoft.AspNetCore.Analyzers
|
||||
{
|
||||
internal static class StartupFacts
|
||||
{
|
||||
public static bool IsConfigureServices(StartupSymbols symbols, IMethodSymbol symbol)
|
||||
{
|
||||
if (symbol == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(symbol));
|
||||
}
|
||||
|
||||
if (symbol.DeclaredAccessibility != Accessibility.Public)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!string.Equals(symbol.Name, SymbolNames.ConfigureServicesMethod, StringComparison.Ordinal))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (symbol.Parameters.Length != 1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (symbol.Parameters[0].Type != symbols.IServiceCollection)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool IsConfigure(StartupSymbols symbols, IMethodSymbol symbol)
|
||||
{
|
||||
if (symbol == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(symbol));
|
||||
}
|
||||
|
||||
if (symbol.DeclaredAccessibility != Accessibility.Public)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (symbol.Name == null || !symbol.Name.StartsWith(SymbolNames.ConfigureMethod, StringComparison.Ordinal))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// IApplicationBuilder can appear in any parameter
|
||||
for (var i = 0; i < symbol.Parameters.Length; i++)
|
||||
{
|
||||
if (symbol.Parameters[i].Type == symbols.IApplicationBuilder)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
// 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.Mvc.Analyzers;
|
||||
using Microsoft.CodeAnalysis;
|
||||
|
||||
namespace Microsoft.AspNetCore.Analyzers
|
||||
{
|
||||
internal class StartupSymbols
|
||||
{
|
||||
public StartupSymbols(Compilation compilation)
|
||||
{
|
||||
IApplicationBuilder = compilation.GetTypeByMetadataName(SymbolNames.IApplicationBuilder);
|
||||
IServiceCollection = compilation.GetTypeByMetadataName(SymbolNames.IServiceCollection);
|
||||
MvcOptions = compilation.GetTypeByMetadataName(SymbolNames.MvcOptions);
|
||||
}
|
||||
|
||||
public INamedTypeSymbol IApplicationBuilder { get; }
|
||||
|
||||
public INamedTypeSymbol IServiceCollection { get; }
|
||||
|
||||
public INamedTypeSymbol MvcOptions { get; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
// 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 UseMvcDiagnosticValidator : StartupDiagnosticValidator
|
||||
{
|
||||
public static UseMvcDiagnosticValidator CreateAndInitialize(CompilationAnalysisContext context, ConcurrentBag<StartupComputedAnalysis> analyses)
|
||||
{
|
||||
if (analyses == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(analyses));
|
||||
}
|
||||
|
||||
var validator = new UseMvcDiagnosticValidator();
|
||||
|
||||
foreach (var mvcOptionsAnalysis in analyses.OfType<MvcOptionsAnalysis>())
|
||||
{
|
||||
// Each analysis of the options is one-per-class (in user code). Find the middleware analysis foreach of the Configure methods
|
||||
// defined by this class and validate.
|
||||
//
|
||||
// Note that this doesn't attempt to handle inheritance scenarios.
|
||||
foreach (var middlewareAnalsysis in analyses.OfType<MiddlewareAnalysis>().Where(m => m.EnclosingType == mvcOptionsAnalysis.EnclosingType))
|
||||
{
|
||||
foreach (var middlewareItem in middlewareAnalsysis.Middleware)
|
||||
{
|
||||
if ((middlewareItem.UseMethod.Name == "UseMvc" || middlewareItem.UseMethod.Name == "UseMvcWithDefaultRoute") &&
|
||||
|
||||
// Report a diagnostic if it's unclear that the user turned off Endpoint Routing.
|
||||
(mvcOptionsAnalysis.EndpointRoutingEnabled == true || mvcOptionsAnalysis.EndpointRoutingEnabled == null))
|
||||
{
|
||||
context.ReportDiagnostic(Diagnostic.Create(
|
||||
StartupAnalzyer.UnsupportedUseMvcWithEndpointRouting,
|
||||
middlewareItem.Operation.Syntax.GetLocation(),
|
||||
middlewareItem.UseMethod.Name,
|
||||
mvcOptionsAnalysis.ConfigureServicesMethod.Name));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return validator;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -60,5 +60,17 @@ namespace Microsoft.AspNetCore.Mvc.Analyzers
|
|||
public const string ProducesResponseTypeAttribute = "Microsoft.AspNetCore.Mvc.ProducesResponseTypeAttribute";
|
||||
|
||||
public const string RenderPartialMethod = "RenderPartial";
|
||||
|
||||
public const string IApplicationBuilder = "Microsoft.AspNetCore.Builder.IApplicationBuilder";
|
||||
|
||||
public const string IServiceCollection = "Microsoft.Extensions.DependencyInjection.IServiceCollection";
|
||||
|
||||
public const string MvcOptions = "Microsoft.AspNetCore.Mvc.MvcOptions";
|
||||
|
||||
public const string EnableEndpointRoutingProperty = "EnableEndpointRouting";
|
||||
|
||||
public const string ConfigureServicesMethod = "ConfigureServices";
|
||||
|
||||
public const string ConfigureMethod = "Configure";
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,218 @@
|
|||
// 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 System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Analyzer.Testing;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Analyzers
|
||||
{
|
||||
public class StartupAnalyzerTest
|
||||
{
|
||||
public StartupAnalyzerTest()
|
||||
{
|
||||
StartupAnalyzer = new StartupAnalzyer();
|
||||
StartupAnalyzer.StartupFilePredicate = path => path.Equals("Test.cs", StringComparison.Ordinal);
|
||||
|
||||
Runner = new MvcDiagnosticAnalyzerRunner(StartupAnalyzer);
|
||||
|
||||
Analyses = new ConcurrentBag<StartupComputedAnalysis>();
|
||||
ConfigureServicesMethods = new ConcurrentBag<IMethodSymbol>();
|
||||
ConfigureMethods = new ConcurrentBag<IMethodSymbol>();
|
||||
StartupAnalyzer.AnalysisStarted += (sender, analysis) => Analyses.Add(analysis);
|
||||
StartupAnalyzer.ConfigureServicesMethodFound += (sender, method) => ConfigureServicesMethods.Add(method);
|
||||
StartupAnalyzer.ConfigureMethodFound += (sender, method) => ConfigureMethods.Add(method);
|
||||
}
|
||||
|
||||
private StartupAnalzyer StartupAnalyzer { get; }
|
||||
|
||||
private MvcDiagnosticAnalyzerRunner Runner { get; }
|
||||
|
||||
private ConcurrentBag<StartupComputedAnalysis> Analyses { get; }
|
||||
|
||||
private ConcurrentBag<IMethodSymbol> ConfigureServicesMethods { get; }
|
||||
|
||||
private ConcurrentBag<IMethodSymbol> ConfigureMethods { get; }
|
||||
|
||||
[Fact]
|
||||
public async Task StartupAnalyzer_FindsStartupMethods_StartupSignatures_Standard()
|
||||
{
|
||||
// Arrange
|
||||
var source = ReadSource("StartupSignatures_Standard");
|
||||
|
||||
// Act
|
||||
var diagnostics = await Runner.GetDiagnosticsAsync(source.Source);
|
||||
|
||||
// Assert
|
||||
Assert.Empty(diagnostics);
|
||||
|
||||
Assert.Collection(ConfigureServicesMethods, m => Assert.Equal("ConfigureServices", m.Name));
|
||||
Assert.Collection(ConfigureMethods, m => Assert.Equal("Configure", m.Name));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task StartupAnalyzer_FindsStartupMethods_StartupSignatures_MoreVariety()
|
||||
{
|
||||
// Arrange
|
||||
var source = ReadSource("StartupSignatures_MoreVariety");
|
||||
|
||||
// Act
|
||||
var diagnostics = await Runner.GetDiagnosticsAsync(source.Source);
|
||||
|
||||
// Assert
|
||||
Assert.Empty(diagnostics);
|
||||
|
||||
Assert.Collection(
|
||||
ConfigureServicesMethods.OrderBy(m => m.Name),
|
||||
m => Assert.Equal("ConfigureServices", m.Name));
|
||||
|
||||
Assert.Collection(
|
||||
ConfigureMethods.OrderBy(m => m.Name),
|
||||
m => Assert.Equal("Configure", m.Name),
|
||||
m => Assert.Equal("ConfigureProduction", m.Name));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task StartupAnalyzer_MvcOptionsAnalysis_UseMvc_FindsEndpointRoutingDisabled()
|
||||
{
|
||||
// Arrange
|
||||
var source = ReadSource("MvcOptions_UseMvcWithDefaultRouteAndEndpointRoutingDisabled");
|
||||
|
||||
// Act
|
||||
var diagnostics = await Runner.GetDiagnosticsAsync(source.Source);
|
||||
|
||||
// Assert
|
||||
var mvcOptionsAnalysis = Assert.Single(Analyses.OfType<MvcOptionsAnalysis>());
|
||||
Assert.False(mvcOptionsAnalysis.EndpointRoutingEnabled);
|
||||
|
||||
var middlewareAnalysis = Assert.Single(Analyses.OfType<MiddlewareAnalysis>());
|
||||
var middleware = Assert.Single(middlewareAnalysis.Middleware);
|
||||
Assert.Equal("UseMvcWithDefaultRoute", middleware.UseMethod.Name);
|
||||
|
||||
Assert.Empty(diagnostics);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task StartupAnalyzer_MvcOptionsAnalysis_AddMvcOptions_FindsEndpointRoutingDisabled()
|
||||
{
|
||||
// Arrange
|
||||
var source = ReadSource("MvcOptions_UseMvcWithDefaultRouteAndAddMvcOptionsEndpointRoutingDisabled");
|
||||
|
||||
// Act
|
||||
var diagnostics = await Runner.GetDiagnosticsAsync(source.Source);
|
||||
|
||||
// Assert
|
||||
var mvcOptionsAnalysis = Assert.Single(Analyses.OfType<MvcOptionsAnalysis>());
|
||||
Assert.False(mvcOptionsAnalysis.EndpointRoutingEnabled);
|
||||
|
||||
var middlewareAnalysis = Assert.Single(Analyses.OfType<MiddlewareAnalysis>());
|
||||
var middleware = Assert.Single(middlewareAnalysis.Middleware);
|
||||
Assert.Equal("UseMvcWithDefaultRoute", middleware.UseMethod.Name);
|
||||
|
||||
Assert.Empty(diagnostics);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("MvcOptions_UseMvc", "UseMvc")]
|
||||
[InlineData("MvcOptions_UseMvcAndConfiguredRoutes", "UseMvc")]
|
||||
[InlineData("MvcOptions_UseMvcWithDefaultRoute", "UseMvcWithDefaultRoute")]
|
||||
public async Task StartupAnalyzer_MvcOptionsAnalysis_FindsEndpointRoutingEnabled(string sourceFileName, string mvcMiddlewareName)
|
||||
{
|
||||
// Arrange
|
||||
var source = ReadSource(sourceFileName);
|
||||
|
||||
// Act
|
||||
var diagnostics = await Runner.GetDiagnosticsAsync(source.Source);
|
||||
|
||||
// Assert
|
||||
var mvcOptionsAnalysis = Assert.Single(Analyses.OfType<MvcOptionsAnalysis>());
|
||||
Assert.Null(mvcOptionsAnalysis.EndpointRoutingEnabled);
|
||||
|
||||
var middlewareAnalysis = Assert.Single(Analyses.OfType<MiddlewareAnalysis>());
|
||||
var middleware = Assert.Single(middlewareAnalysis.Middleware);
|
||||
Assert.Equal(mvcMiddlewareName, middleware.UseMethod.Name);
|
||||
|
||||
Assert.Collection(
|
||||
diagnostics,
|
||||
diagnostic =>
|
||||
{
|
||||
Assert.Same(StartupAnalzyer.UnsupportedUseMvcWithEndpointRouting, diagnostic.Descriptor);
|
||||
AnalyzerAssert.DiagnosticLocation(source.DefaultMarkerLocation, diagnostic.Location);
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task StartupAnalyzer_MvcOptionsAnalysis_MultipleMiddleware()
|
||||
{
|
||||
// Arrange
|
||||
var source = ReadSource("MvcOptions_UseMvcWithOtherMiddleware");
|
||||
|
||||
// Act
|
||||
var diagnostics = await Runner.GetDiagnosticsAsync(source.Source);
|
||||
|
||||
// Assert
|
||||
var mvcOptionsAnalysis = Assert.Single(Analyses.OfType<MvcOptionsAnalysis>());
|
||||
Assert.Null(mvcOptionsAnalysis.EndpointRoutingEnabled);
|
||||
|
||||
var middlewareAnalysis = Assert.Single(Analyses.OfType<MiddlewareAnalysis>());
|
||||
|
||||
Assert.Collection(
|
||||
middlewareAnalysis.Middleware,
|
||||
item => Assert.Equal("UseAuthorization", item.UseMethod.Name),
|
||||
item => Assert.Equal("UseMiddleware", item.UseMethod.Name),
|
||||
item => Assert.Equal("UseMvc", item.UseMethod.Name),
|
||||
item => Assert.Equal("UseRouting", item.UseMethod.Name),
|
||||
item => Assert.Equal("UseEndpoints", item.UseMethod.Name));
|
||||
|
||||
Assert.Collection(
|
||||
diagnostics,
|
||||
diagnostic =>
|
||||
{
|
||||
Assert.Same(StartupAnalzyer.UnsupportedUseMvcWithEndpointRouting, diagnostic.Descriptor);
|
||||
AnalyzerAssert.DiagnosticLocation(source.DefaultMarkerLocation, diagnostic.Location);
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task StartupAnalyzer_MvcOptionsAnalysis_MultipleUseMvc()
|
||||
{
|
||||
// Arrange
|
||||
var source = ReadSource("MvcOptions_UseMvcMultiple");
|
||||
|
||||
// Act
|
||||
var diagnostics = await Runner.GetDiagnosticsAsync(source.Source);
|
||||
|
||||
// Assert
|
||||
var mvcOptionsAnalysis = Assert.Single(Analyses.OfType<MvcOptionsAnalysis>());
|
||||
Assert.Null(mvcOptionsAnalysis.EndpointRoutingEnabled);
|
||||
|
||||
Assert.Collection(
|
||||
diagnostics,
|
||||
diagnostic =>
|
||||
{
|
||||
Assert.Same(StartupAnalzyer.UnsupportedUseMvcWithEndpointRouting, diagnostic.Descriptor);
|
||||
AnalyzerAssert.DiagnosticLocation(source.MarkerLocations["MM1"], diagnostic.Location);
|
||||
},
|
||||
diagnostic =>
|
||||
{
|
||||
Assert.Same(StartupAnalzyer.UnsupportedUseMvcWithEndpointRouting, diagnostic.Descriptor);
|
||||
AnalyzerAssert.DiagnosticLocation(source.MarkerLocations["MM2"], diagnostic.Location);
|
||||
},
|
||||
diagnostic =>
|
||||
{
|
||||
Assert.Same(StartupAnalzyer.UnsupportedUseMvcWithEndpointRouting, diagnostic.Descriptor);
|
||||
AnalyzerAssert.DiagnosticLocation(source.MarkerLocations["MM3"], diagnostic.Location);
|
||||
});
|
||||
}
|
||||
|
||||
private TestSource ReadSource(string fileName)
|
||||
{
|
||||
return MvcTestSource.Read(nameof(StartupAnalyzerTest), fileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
// 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 MvcOptions_UseMvc
|
||||
{
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
services.AddMvc();
|
||||
}
|
||||
|
||||
public void Configure(IApplicationBuilder app)
|
||||
{
|
||||
/*MM*/app.UseMvc();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
// 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 MvcOptions_UseMvcAndConfiguredRoutes
|
||||
{
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
services.AddMvc();
|
||||
}
|
||||
|
||||
public void Configure(IApplicationBuilder app)
|
||||
{
|
||||
/*MM*/app.UseMvc(routes =>
|
||||
{
|
||||
routes.MapRoute("Name", "Template");
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
// 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.Authorization;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Microsoft.AspNetCore.Analyzers.TestFiles.StartupAnalyzerTest
|
||||
{
|
||||
public class MvcOptions_UseMvcMultiple
|
||||
{
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
services.AddMvc();
|
||||
}
|
||||
|
||||
public void Configure(IApplicationBuilder app)
|
||||
{
|
||||
/*MM1*/app.UseMvcWithDefaultRoute();
|
||||
|
||||
app.UseAuthorization();
|
||||
app.UseMiddleware<AuthorizationMiddleware>();
|
||||
|
||||
/*MM2*/app.UseMvc();
|
||||
|
||||
app.UseRouting();
|
||||
app.UseEndpoints(endpoints =>
|
||||
{
|
||||
});
|
||||
|
||||
/*MM3*/app.UseMvc();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
// 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 MvcOptions_UseMvcWithDefaultRoute
|
||||
{
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
services.AddMvc();
|
||||
}
|
||||
|
||||
public void Configure(IApplicationBuilder app)
|
||||
{
|
||||
/*MM*/app.UseMvcWithDefaultRoute();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
// 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 MvcOptions_UseMvcWithDefaultRouteAndAddMvcOptionsEndpointRoutingDisabled
|
||||
{
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
services.AddMvc().AddMvcOptions(options => options.EnableEndpointRouting = false);
|
||||
}
|
||||
|
||||
public void Configure(IApplicationBuilder app)
|
||||
{
|
||||
app.UseMvcWithDefaultRoute();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
// 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 MvcOptions_UseMvcWithDefaultRouteAndEndpointRoutingDisabled
|
||||
{
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
services.AddMvc(options => options.EnableEndpointRouting = false);
|
||||
}
|
||||
|
||||
public void Configure(IApplicationBuilder app)
|
||||
{
|
||||
app.UseMvcWithDefaultRoute();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
// 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.Authorization;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Microsoft.AspNetCore.Analyzers.TestFiles.StartupAnalyzerTest
|
||||
{
|
||||
public class MvcOptions_UseMvcWithOtherMiddleware
|
||||
{
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
services.AddMvc();
|
||||
}
|
||||
|
||||
public void Configure(IApplicationBuilder app)
|
||||
{
|
||||
app.UseAuthorization();
|
||||
app.UseMiddleware<AuthorizationMiddleware>();
|
||||
|
||||
/*MM*/app.UseMvc();
|
||||
|
||||
app.UseRouting();
|
||||
app.UseEndpoints(endpoints =>
|
||||
{
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
// 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.Text;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Microsoft.AspNetCore.Analyzers.TestFiles.StartupAnalyzerTest
|
||||
{
|
||||
public class StartupSignatures_MoreVariety
|
||||
{
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
}
|
||||
|
||||
public void ConfigureServices(IServiceCollection services, StringBuilder s) // Ignored
|
||||
{
|
||||
}
|
||||
|
||||
public void Configure(StringBuilder s) // Ignored,
|
||||
{
|
||||
}
|
||||
|
||||
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
|
||||
{
|
||||
}
|
||||
|
||||
public void ConfigureProduction(IWebHostEnvironment env, IApplicationBuilder app)
|
||||
{
|
||||
}
|
||||
|
||||
private void Configure(IApplicationBuilder app) // Ignored
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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 StartupSignatures_Standard
|
||||
{
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
}
|
||||
|
||||
public void Configure(IApplicationBuilder app)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue