-
Notifications
You must be signed in to change notification settings - Fork 10.3k
Warn that UseStartup/Configure/ConfigureWebHost not supported on WebApplicationBuilder #35884
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Warn that UseStartup/Configure/ConfigureWebHost not supported on WebApplicationBuilder #35884
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks great!
src/Framework/Analyzer/src/WebApplicationBuilder/DiagnosticDescriptors.cs
Outdated
Show resolved
Hide resolved
internal static readonly DiagnosticDescriptor DoNotUseConfigureWebHostWithConfigureHostBuilder = new( | ||
"ASP0005", | ||
"Do not use ConfigureWebHost with WebApplicationBuilder.Host", | ||
"ConfigureWebHost cannot be used with WebApplicationBuilder.Host", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we say more about what the right thing to do would be? `Consider blah instead..."? @davidfowl what's the alternative?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah I wasn't sure on the wording that would be wanted, so just went with something basic as a starting point.
|
||
public partial class WebApplicationBuilderAnalyzer : DiagnosticAnalyzer | ||
{ | ||
private static void DisallowConfigureHostBuilderConfigureWebHost( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Btw, I'm super ok putting this in the same file as the anlayzer. The only reason I thought partials made sense for the minimal action one was because it had a bunch of different code to run per analysis.
IMethodSymbol methodSymbol, | ||
INamedTypeSymbol disallowedReceiverType, | ||
string disallowedMethodName, | ||
params INamedTypeSymbol[] disallowedMethodTypes) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might want to avoid the params
since it allocates per call. We could statically cache the array
src/Framework/Analyzer/src/WebApplicationBuilder/WebApplicationBuilderAnalyzer.cs
Outdated
Show resolved
Hide resolved
return false; | ||
} | ||
|
||
return disallowedMethodTypes.Any(type => SymbolEqualityComparer.Default.Equals(type, methodSymbol.ContainingType)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we use a regular for loop? We should treat all of the analyzers as if they were running in the hot path all the time.
src/Framework/Analyzer/src/WebApplicationBuilder/WebApplicationBuilderAnalyzer.cs
Outdated
Show resolved
Hide resolved
src/Framework/Analyzer/src/WebApplicationBuilder/WebApplicationBuilderAnalyzer.cs
Outdated
Show resolved
Hide resolved
public async Task WebApplicationBuilder_WebHostWithConfigureWithContext_ProducesDiagnostics() | ||
{ | ||
// Arrange | ||
var source = TestSource.Read(@" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know it doesn't matter to the implementation, but could we add one test with producing diagnostics in a non-top level Program?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure - didn't think of that.
I want to feature creep this PR as I realize there are more APIs I want to block but this is awesome |
😄 I'd be happy to add some more similar patterns as a follow-up post-merge if you've got a laundry list. |
public static void Main(string[] args) | ||
{ | ||
var builder = WebApplication.CreateBuilder(args); | ||
/*MM*/builder.Host.ConfigureWebHost(webHostBuilder => { }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is the marker here supposed to be on the line start instead of at the problematic invocation?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The pattern I've been following is to emit the diagnostic at the point where the problematic invocation exists so if the user clicks on the diagnostic's location in the build output the cursor will be directed to the place where they need to make the fix.
It also makes it easier to write codefixes associated with the analyzer because you can get the syntax at the problematic location right away.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah I figured that would be the case. I originally put it before ConfigureWebHost
, but then the tests failed even though I was just using the syntax given to the analyzer to get the location for the invocation. I'll dig around more and see if I can work out why there's a mismatch when I do that so the warning is in the best place.
...ramework/Analyzer/test/WebApplicationBuilder/DisallowConfigureWebHostBuilderConfigureTest.cs
Outdated
Show resolved
Hide resolved
...amework/Analyzer/test/WebApplicationBuilder/DisallowConfigureWebHostBuilderUseStartupTest.cs
Outdated
Show resolved
Hide resolved
return; | ||
} | ||
|
||
INamedTypeSymbol[] configureTypes = { wellKnownTypes.WebHostBuilderExtensions }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Couldn't statically cache as the compilation is needed to get the well-known types, but I guess the lifetime of the class is "long enough" that these locals being reused in the lambda are OK?
@pranavkm you are the gate here |
@captainsafia you as well. |
36a5bae
to
dedc5d7
Compare
var methodName = operation.Syntax | ||
.DescendantNodes() | ||
.OfType<SimpleNameSyntax>() | ||
.Where(node => node is IdentifierNameSyntax || node is GenericNameSyntax) | ||
.Where(node => string.Equals(node.Identifier.Value as string, operation.TargetMethod.Name, StringComparison.Ordinal)) | ||
.FirstOrDefault(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Happy to refactor this if there's a better way I didn't work out for myself.
I assumed that using LINQ here was OK as we're already on the path where a diagnostic is going to be fired.
using Microsoft.Extensions.Hosting; | ||
var builder = WebApplication.CreateBuilder(); | ||
builder.Host | ||
.ConfigureServices(services => { }) // Because ConfigureServices() returns IHostBuilder, the type gets erased |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Happy to remove this test if it doesn't add any value. It started as my check the analyzer did work, but then realising that as the receiver type on ConfigureWebHost()
became IHostBuilder
it could no longer be detected.
Alternatively I could try and make it actually fire, but that would mean walking up the invocation chain and trying to find the WebApplicationBuilder.Host at the root, but I'm not sure that's worth adding that additional complexity to try and cover so many possible usage patterns.
dedc5d7
to
358431d
Compare
src/Framework/AspNetCoreAnalyzers/src/Analyzers/DiagnosticDescriptors.cs
Show resolved
Hide resolved
...CoreAnalyzers/test/WebApplicationBuilder/DisallowConfigureHostBuilderConfigureWebHostTest.cs
Show resolved
Hide resolved
} | ||
} | ||
|
||
// GetReceiverType() adapted from IOperationExtensions.GetReceiverType in dotnet/roslyn-analyzers. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: We can move this to src/Shared/Roslyn
.
Add analyzers that warn on incorrect usage of UseStartup(), Configure() and ConfigureWebHost() when using WebApplicationBuilder. Resolves dotnet#35814.
c2b5322
to
79f7251
Compare
/azp run |
Azure Pipelines successfully started running 3 pipeline(s). |
PR Title
Add WebApplicationBuilder analyzers for unsupported methods
PR Description
Add analyzers that warn on incorrect usage of
UseStartup()
,Configure()
andConfigureWebHost()
when usingWebApplicationBuilder.Host
andWebApplicationBuilder.WebHost
.TODO
Add tests for existing startup patterns prior to .NET 6 to verify they do not generate false positivesRefactor analyzer to reduce duplication in detecting similar usage patternsFixes #35814