Skip to content

Commit 594cfb3

Browse files
authored
Route tooling redux (dotnet#44077)
1 parent 92ff9a1 commit 594cfb3

File tree

86 files changed

+14127
-28
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

86 files changed

+14127
-28
lines changed

Diff for: AspNetCore.sln

+28-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
Microsoft Visual Studio Solution File, Format Version 12.00
1+

2+
Microsoft Visual Studio Solution File, Format Version 12.00
23
# Visual Studio Version 17
34
VisualStudioVersion = 17.0.31606.5
45
MinimumVisualStudioVersion = 15.0.26124.0
@@ -1745,6 +1746,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebTransportInteractiveSamp
17451746
EndProject
17461747
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Templates.Blazor.WebAssembly.Auth.Tests", "src\ProjectTemplates\test\Templates.Blazor.WebAssembly.Auth.Tests\Templates.Blazor.WebAssembly.Auth.Tests.csproj", "{3A6FD623-F7F3-404B-8A39-CAFB40CA6A08}"
17471748
EndProject
1749+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{890B5210-48EF-488F-93A2-F13BCB07C780}"
1750+
EndProject
1751+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebAppSample", "src\Framework\AspNetCoreAnalyzers\samples\WebAppSample\WebAppSample.csproj", "{A8E2AB77-8F57-47C2-A961-2F316793CAFF}"
1752+
EndProject
1753+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{F43CC5EA-6032-4A11-A9B2-6D48CB5EB082}"
1754+
EndProject
17481755
Global
17491756
GlobalSection(SolutionConfigurationPlatforms) = preSolution
17501757
Debug|Any CPU = Debug|Any CPU
@@ -10490,6 +10497,22 @@ Global
1049010497
{3A6FD623-F7F3-404B-8A39-CAFB40CA6A08}.Release|x64.Build.0 = Release|Any CPU
1049110498
{3A6FD623-F7F3-404B-8A39-CAFB40CA6A08}.Release|x86.ActiveCfg = Release|Any CPU
1049210499
{3A6FD623-F7F3-404B-8A39-CAFB40CA6A08}.Release|x86.Build.0 = Release|Any CPU
10500+
{A8E2AB77-8F57-47C2-A961-2F316793CAFF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
10501+
{A8E2AB77-8F57-47C2-A961-2F316793CAFF}.Debug|Any CPU.Build.0 = Debug|Any CPU
10502+
{A8E2AB77-8F57-47C2-A961-2F316793CAFF}.Debug|arm64.ActiveCfg = Debug|Any CPU
10503+
{A8E2AB77-8F57-47C2-A961-2F316793CAFF}.Debug|arm64.Build.0 = Debug|Any CPU
10504+
{A8E2AB77-8F57-47C2-A961-2F316793CAFF}.Debug|x64.ActiveCfg = Debug|Any CPU
10505+
{A8E2AB77-8F57-47C2-A961-2F316793CAFF}.Debug|x64.Build.0 = Debug|Any CPU
10506+
{A8E2AB77-8F57-47C2-A961-2F316793CAFF}.Debug|x86.ActiveCfg = Debug|Any CPU
10507+
{A8E2AB77-8F57-47C2-A961-2F316793CAFF}.Debug|x86.Build.0 = Debug|Any CPU
10508+
{A8E2AB77-8F57-47C2-A961-2F316793CAFF}.Release|Any CPU.ActiveCfg = Release|Any CPU
10509+
{A8E2AB77-8F57-47C2-A961-2F316793CAFF}.Release|Any CPU.Build.0 = Release|Any CPU
10510+
{A8E2AB77-8F57-47C2-A961-2F316793CAFF}.Release|arm64.ActiveCfg = Release|Any CPU
10511+
{A8E2AB77-8F57-47C2-A961-2F316793CAFF}.Release|arm64.Build.0 = Release|Any CPU
10512+
{A8E2AB77-8F57-47C2-A961-2F316793CAFF}.Release|x64.ActiveCfg = Release|Any CPU
10513+
{A8E2AB77-8F57-47C2-A961-2F316793CAFF}.Release|x64.Build.0 = Release|Any CPU
10514+
{A8E2AB77-8F57-47C2-A961-2F316793CAFF}.Release|x86.ActiveCfg = Release|Any CPU
10515+
{A8E2AB77-8F57-47C2-A961-2F316793CAFF}.Release|x86.Build.0 = Release|Any CPU
1049310516
EndGlobalSection
1049410517
GlobalSection(SolutionProperties) = preSolution
1049510518
HideSolutionNode = FALSE
@@ -11264,7 +11287,7 @@ Global
1126411287
{B5D98AEB-9409-4280-8225-9C1EC6A791B2} = {4DA84F2B-1948-439B-85AB-E99E31331A9C}
1126511288
{2A150BE3-D7DC-4E2A-8399-6EBAB77DEF00} = {B5D98AEB-9409-4280-8225-9C1EC6A791B2}
1126611289
{D5F4D764-887D-4EB3-8D00-FCBE23FFDBBC} = {B5D98AEB-9409-4280-8225-9C1EC6A791B2}
11267-
{40F493E2-FE59-4787-BE44-3AED39D585BF} = {4DA84F2B-1948-439B-85AB-E99E31331A9C}
11290+
{40F493E2-FE59-4787-BE44-3AED39D585BF} = {F43CC5EA-6032-4A11-A9B2-6D48CB5EB082}
1126811291
{97F9F7E9-56DA-49FE-B672-499E68EBB9DA} = {41B519F7-CF19-4FB4-B96C-E38A7EF45F70}
1126911292
{6F335C66-C1D6-45FA-8529-6503B7CD42CC} = {97F9F7E9-56DA-49FE-B672-499E68EBB9DA}
1127011293
{71A54D7F-245F-43C2-B429-342D80AC6F23} = {97F9F7E9-56DA-49FE-B672-499E68EBB9DA}
@@ -11352,6 +11375,9 @@ Global
1135211375
{07FDBE0D-B7A1-43DE-B120-F699C30E7CEF} = {E19E55A2-1562-47A7-8EA6-B51F2CA0CC4C}
1135311376
{BA649043-EF2B-42DC-B422-A46127BE8296} = {7B976D8F-EA31-4C0B-97BD-DFD9B3CC86FB}
1135411377
{3A6FD623-F7F3-404B-8A39-CAFB40CA6A08} = {08D53E58-4AAE-40C4-8497-63EC8664F304}
11378+
{890B5210-48EF-488F-93A2-F13BCB07C780} = {4DA84F2B-1948-439B-85AB-E99E31331A9C}
11379+
{A8E2AB77-8F57-47C2-A961-2F316793CAFF} = {890B5210-48EF-488F-93A2-F13BCB07C780}
11380+
{F43CC5EA-6032-4A11-A9B2-6D48CB5EB082} = {4DA84F2B-1948-439B-85AB-E99E31331A9C}
1135511381
EndGlobalSection
1135611382
GlobalSection(ExtensibilityGlobals) = postSolution
1135711383
SolutionGuid = {3E8720B3-DBDD-498C-B383-2CC32A054E8F}

Diff for: NuGet.config

+3
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@
1818
<add key="dotnet31-transport" value="https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet3.1-transport/nuget/v3/index.json" />
1919
<!-- Used for the Rich Navigation indexing task -->
2020
<add key="richnav" value="https://pkgs.dev.azure.com/azure-public/vside/_packaging/vs-buildservices/nuget/v3/index.json" />
21+
<!-- Preview VS bits for route tooling. Will be removed in future when packages referenced by Roslyn move out of preview. -->
22+
<add key="vssdk" value="https://pkgs.dev.azure.com/azure-public/vside/_packaging/vssdk/nuget/v3/index.json" />
23+
<add key="vs-impl" value="https://pkgs.dev.azure.com/azure-public/vside/_packaging/vs-impl/nuget/v3/index.json" />
2124
</packageSources>
2225
<disabledPackageSources>
2326
<clear />

Diff for: eng/Dependencies.props

+1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ and are generated based on the last package release.
2121
<LatestPackageReference Include="Microsoft.CodeAnalysis.Common" />
2222
<LatestPackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" />
2323
<LatestPackageReference Include="Microsoft.CodeAnalysis.CSharp" />
24+
<LatestPackageReference Include="Microsoft.CodeAnalysis.ExternalAccess.AspNetCore" />
2425
<LatestPackageReference Include="Microsoft.CodeAnalysis.Razor" />
2526
<LatestPackageReference Include="Microsoft.CSharp" />
2627
<LatestPackageReference Include="Microsoft.Extensions.Caching.Abstractions" />

Diff for: eng/Versions.props

+1
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,7 @@
207207
-->
208208
<Analyzer_MicrosoftCodeAnalysisCSharpVersion>3.3.1</Analyzer_MicrosoftCodeAnalysisCSharpVersion>
209209
<Analyzer_MicrosoftCodeAnalysisCSharpWorkspacesVersion>3.3.1</Analyzer_MicrosoftCodeAnalysisCSharpWorkspacesVersion>
210+
<MicrosoftCodeAnalysisExternalAccessAspNetCoreVersion>4.4.0-3.22472.13</MicrosoftCodeAnalysisExternalAccessAspNetCoreVersion>
210211
<MicrosoftCodeAnalysisCommonVersion>4.4.0-3.22472.13</MicrosoftCodeAnalysisCommonVersion>
211212
<MicrosoftCodeAnalysisCSharpVersion>4.4.0-3.22472.13</MicrosoftCodeAnalysisCSharpVersion>
212213
<MicrosoftCodeAnalysisCSharpWorkspacesVersion>4.4.0-3.22472.13</MicrosoftCodeAnalysisCSharpWorkspacesVersion>

Diff for: src/Analyzers/Microsoft.AspNetCore.Analyzer.Testing/src/DiagnosticProject.cs

+32-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4+
using System;
45
using System.Collections.Generic;
56
using System.Linq;
67
using System.Reflection;
78
using Microsoft.CodeAnalysis;
9+
using Microsoft.CodeAnalysis.Diagnostics;
810
using Microsoft.CodeAnalysis.Text;
911
using Microsoft.Extensions.DependencyModel;
1012
using Microsoft.Extensions.DependencyModel.Resolution;
@@ -26,15 +28,17 @@ public class DiagnosticProject
2628
private static readonly ICompilationAssemblyResolver _assemblyResolver = new AppBaseCompilationAssemblyResolver();
2729
private static readonly Dictionary<Assembly, Solution> _solutionCache = new Dictionary<Assembly, Solution>();
2830

29-
public static Project Create(Assembly testAssembly, string[] sources)
31+
public static Project Create(Assembly testAssembly, string[] sources, Func<Workspace> workspaceFactory = null, Type analyzerReference = null)
3032
{
3133
Solution solution;
3234
lock (_solutionCache)
3335
{
3436
if (!_solutionCache.TryGetValue(testAssembly, out solution))
3537
{
38+
workspaceFactory ??= CreateWorkspace;
39+
3640
var projectId = ProjectId.CreateNewId(debugName: TestProjectName);
37-
solution = new AdhocWorkspace()
41+
solution = workspaceFactory()
3842
.CurrentSolution
3943
.AddProject(projectId, TestProjectName, TestProjectName, LanguageNames.CSharp);
4044

@@ -46,6 +50,13 @@ public static Project Create(Assembly testAssembly, string[] sources)
4650
}
4751
}
4852

53+
if (analyzerReference != null)
54+
{
55+
solution = solution.AddAnalyzerReference(
56+
projectId,
57+
new AnalyzerFileReference(analyzerReference.Assembly.Location, AssemblyLoader.Instance));
58+
}
59+
4960
_solutionCache.Add(testAssembly, solution);
5061
}
5162
}
@@ -68,4 +79,23 @@ public static Project Create(Assembly testAssembly, string[] sources)
6879

6980
return solution.GetProject(testProject);
7081
}
82+
83+
private static Workspace CreateWorkspace()
84+
{
85+
return new AdhocWorkspace();
86+
}
87+
88+
internal sealed class AssemblyLoader : IAnalyzerAssemblyLoader
89+
{
90+
public static AssemblyLoader Instance = new AssemblyLoader();
91+
92+
public void AddDependencyLocation(string fullPath)
93+
{
94+
}
95+
96+
public Assembly LoadFromPath(string fullPath)
97+
{
98+
return Assembly.LoadFrom(fullPath);
99+
}
100+
}
71101
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
#region Namespaces
5+
using Microsoft.AspNetCore.Builder;
6+
using Microsoft.AspNetCore.Http;
7+
using Microsoft.AspNetCore.Mvc;
8+
using Microsoft.Extensions.DependencyInjection;
9+
using Microsoft.Extensions.Logging;
10+
#endregion
11+
12+
[Route("api/[controller]")]
13+
public class TodoController
14+
{
15+
private readonly DbContext _dbContext;
16+
17+
public TodoController(DbContext dbContext) => _dbContext = dbContext;
18+
19+
[HttpGet("{id}")]
20+
public Todo Get(int id) => _dbContext.Todos.Find(id);
21+
22+
[HttpPut]
23+
public void Create([FromBody] Todo todo) => _dbContext.Todos.Add(todo);
24+
25+
[HttpGet("[action]/{page?}")]
26+
public IEnumerable<Todo> Search(int? page, [FromQuery] string text)
27+
{
28+
return _dbContext.Todos
29+
.Where(t => t.Text.Contains(text))
30+
.Skip((page ?? 0) * 10)
31+
.Take(10);
32+
}
33+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
public class DbContext
5+
{
6+
public IList<Todo> Todos { get; } = new List<Todo>();
7+
public IList<Book> Books { get; } = new List<Book>();
8+
}
9+
10+
public static class ListExtensions
11+
{
12+
public static T Find<T>(this IList<T> list, int id)
13+
{
14+
return default!;
15+
}
16+
}
17+
18+
public class Todo
19+
{
20+
public string Text { get; set; }
21+
}
22+
23+
public class Book
24+
{
25+
public string Text { get; set; }
26+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
@page "index/{id}"
2+
@using Microsoft.AspNetCore.Routing.Patterns;
3+
@using System.Text.RegularExpressions;
4+
@using WebAppSample.Pages;
5+
@model IndexModel
6+
7+
@{
8+
Regex.IsMatch("", "[a-z0-9_-]+");
9+
10+
RoutePatternFactory.Parse("index/{id}");
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
using Microsoft.AspNetCore.Mvc;
2+
using Microsoft.AspNetCore.Mvc.RazorPages;
3+
4+
namespace WebAppSample.Pages;
5+
6+
public class IndexModel : PageModel
7+
{
8+
public void OnGet()
9+
{
10+
}
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System.Text.RegularExpressions;
5+
6+
var builder = WebApplication.CreateBuilder(args);
7+
builder.Services.AddControllers();
8+
9+
var app = builder.Build();
10+
var db = new DbContext();
11+
12+
app.MapGet("/users/{userId}/books/{bookId?}", IResult (int userId, int? bookId) =>
13+
{
14+
return bookId != null
15+
? Results.Ok(db.Books.Find(bookId.Value))
16+
: Results.Ok(db.Books);
17+
});
18+
19+
app.MapGet("/posts/{**rest}", (string rest) => $"Routing to {rest}");
20+
app.MapGet("/todos/{id}", (int id) => db.Todos.Find(id));
21+
app.MapGet("/todos/{text}", (string text) => db.Todos.Where(t => t.Text.Contains(text)));
22+
app.MapGet("/posts/{slug:regex(^[a-z0-9_-]+$)}", (string slug) =>
23+
{
24+
return $"Match slug: {Regex.IsMatch(slug, "[a-z0-9_-]+")}";
25+
});
26+
27+
app.MapControllerRoute("Default", "{controller=Home}/{action=Index}/{id?}");
28+
29+
app.Run();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"profiles": {
3+
"WebAppSample": {
4+
"commandName": "Project",
5+
"dotnetRunMessages": true,
6+
"launchBrowser": true,
7+
"applicationUrl": "https://localhost:5001;http://localhost:5000",
8+
"environmentVariables": {
9+
"ASPNETCORE_ENVIRONMENT": "Development"
10+
}
11+
}
12+
}
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<Project Sdk="Microsoft.NET.Sdk.Web">
2+
3+
<PropertyGroup>
4+
<TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
5+
</PropertyGroup>
6+
7+
<ItemGroup>
8+
<ProjectReference Include="..\..\src\CodeFixes\Microsoft.AspNetCore.App.CodeFixes.csproj" />
9+
10+
<!-- Makes analyzer, code fixes, and other Roslyn features available in this project. -->
11+
<!-- Note that VS needs to be reloaded after code changes to get the latest version. -->
12+
<ProjectReference Include="..\..\src\Analyzers\Microsoft.AspNetCore.App.Analyzers.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" SetTargetFramework="TargetFramework=netstandard2.0" />
13+
<ProjectReference Include="..\..\src\CodeFixes\Microsoft.AspNetCore.App.CodeFixes.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" SetTargetFramework="TargetFramework=netstandard2.0" />
14+
</ItemGroup>
15+
16+
<ItemGroup>
17+
<Reference Include="Microsoft.AspNetCore" />
18+
<Reference Include="Microsoft.AspNetCore.Diagnostics" />
19+
<Reference Include="Microsoft.AspNetCore.Hosting" />
20+
<Reference Include="Microsoft.AspNetCore.Http" />
21+
<Reference Include="Microsoft.AspNetCore.Http.Results" />
22+
<Reference Include="Microsoft.AspNetCore.Mvc" />
23+
</ItemGroup>
24+
25+
</Project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"Logging": {
3+
"LogLevel": {
4+
"Default": "Information",
5+
"Microsoft": "Warning",
6+
"Microsoft.Hosting.Lifetime": "Information"
7+
}
8+
}
9+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"Logging": {
3+
"LogLevel": {
4+
"Default": "Information",
5+
"Microsoft": "Warning",
6+
"Microsoft.Hosting.Lifetime": "Information"
7+
}
8+
},
9+
"AllowedHosts": "*"
10+
}

Diff for: src/Framework/AspNetCoreAnalyzers/src/Analyzers/DiagnosticDescriptors.cs

+9
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,15 @@ namespace Microsoft.AspNetCore.Analyzers;
88
[System.Diagnostics.CodeAnalysis.SuppressMessage("MicrosoftCodeAnalysisReleaseTracking", "RS2008:Enable analyzer release tracking")]
99
internal static class DiagnosticDescriptors
1010
{
11+
internal static readonly DiagnosticDescriptor RoutePatternIssue = new(
12+
"RP0001",
13+
new LocalizableResourceString(nameof(Resources.Invalid_Route_pattern), Resources.ResourceManager, typeof(Resources)),
14+
new LocalizableResourceString(nameof(Resources.Route_issue_0), Resources.ResourceManager, typeof(Resources)),
15+
"Style",
16+
DiagnosticSeverity.Warning,
17+
isEnabledByDefault: true,
18+
helpLinkUri: "https://aka.ms/aspnet/analyzers");
19+
1120
internal static readonly DiagnosticDescriptor DoNotUseModelBindingAttributesOnRouteHandlerParameters = new(
1221
"ASP0003",
1322
"Do not use model binding attributes with route handlers",

Diff for: src/Framework/AspNetCoreAnalyzers/src/Analyzers/Microsoft.AspNetCore.App.Analyzers.csproj

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
<ItemGroup>
1313
<Reference Include="Microsoft.CodeAnalysis.CSharp" PrivateAssets="All" />
14+
<Reference Include="Microsoft.CodeAnalysis.ExternalAccess.AspNetCore" />
1415

1516
<InternalsVisibleTo Include="Microsoft.AspNetCore.App.Analyzers.Test" />
1617
<InternalsVisibleTo Include="Microsoft.AspNetCore.App.CodeFixes" />

0 commit comments

Comments
 (0)