Repository: davidfowl/uController Branch: main Commit: a144fb1b276e Files: 47 Total size: 427.6 KB Directory structure: gitextract_a4yt5j7o/ ├── .gitattributes ├── .github/ │ └── workflows/ │ └── ci.yaml ├── .gitignore ├── .vscode/ │ ├── launch.json │ ├── settings.json │ └── tasks.json ├── Directory.Build.props ├── GeneratedOutput/ │ └── RouteBuilderExtensions.g.cs ├── README.md ├── nuget.config ├── samples/ │ ├── .vscode/ │ │ ├── launch.json │ │ └── tasks.json │ ├── MapTodos.cs │ ├── Program.cs │ ├── Sample.csproj │ ├── Wrapper.cs │ └── appsettings.json ├── src/ │ └── uController.SourceGenerator/ │ ├── AnalyzerReleases.Shipped.md │ ├── AnalyzerReleases.Unshipped.md │ ├── AwaitableInfo.cs │ ├── CodeGenerationTypes.cs │ ├── HttpModel.cs │ ├── MinimalCodeGenerator.cs │ ├── Reflection/ │ │ ├── MetadataLoadContext.cs │ │ ├── RoslynAssembly.cs │ │ ├── RoslynConstructorInfo.cs │ │ ├── RoslynCustomAttributeData.cs │ │ ├── RoslynExtensions.cs │ │ ├── RoslynFieldInfo.cs │ │ ├── RoslynMemberInfo.cs │ │ ├── RoslynMethodInfo.cs │ │ ├── RoslynParameterInfo.cs │ │ ├── RoslynPropertyInfo.cs │ │ ├── RoslynType.cs │ │ └── SharedUtilities.cs │ ├── ReflectionExtensions.cs │ ├── RoutePattern.cs │ ├── WellKnownTypes.cs │ ├── uController.SourceGenerator.csproj │ └── uControllerGenerator.cs ├── test/ │ └── uController.SourceGenerator.Tests/ │ ├── IntegrationTests.cs │ ├── SharedTypes.cs │ ├── SourceKey.cs │ ├── Usings.cs │ └── uController.SourceGenerator.Tests.csproj ├── uController.sln └── version.json ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitattributes ================================================ *.doc diff=astextplain *.DOC diff=astextplain *.docx diff=astextplain *.DOCX diff=astextplain *.dot diff=astextplain *.DOT diff=astextplain *.pdf diff=astextplain *.PDF diff=astextplain *.rtf diff=astextplain *.RTF diff=astextplain *.jpg binary *.png binary *.gif binary *.cs text=auto diff=csharp *.vb text=auto *.resx text=auto *.c text=auto *.cpp text=auto *.cxx text=auto *.h text=auto *.hxx text=auto *.py text=auto *.rb text=auto *.java text=auto *.html text=auto *.htm text=auto *.css text=auto *.scss text=auto *.sass text=auto *.less text=auto *.js text=auto *.lisp text=auto *.clj text=auto *.sql text=auto *.php text=auto *.lua text=auto *.m text=auto *.asm text=auto *.erl text=auto *.fs text=auto *.fsx text=auto *.hs text=auto *.csproj text=auto *.vbproj text=auto *.fsproj text=auto *.dbproj text=auto *.sln text=auto eol=crlf *.sh eol=lf ================================================ FILE: .github/workflows/ci.yaml ================================================ name: CI on: [push, pull_request] jobs: build: runs-on: windows-latest steps: - uses: actions/checkout@v1 - name: Setup .NET Core SDK uses: actions/setup-dotnet@v3 with: dotnet-version: 7.0.x dotnet-quality: 'ga' - uses: aarnott/nbgv@v0.4.0 with: setAllVars: true - name: dotnet build run: dotnet build uController.sln -c Release - name: dotnet test run: dotnet test uController.sln -c Release --no-build - name: dotnet pack run: dotnet pack uController.sln -c Release --no-build --include-source --include-symbols - name: setup nuget if: github.event_name == 'push' && github.ref == 'refs/heads/main' uses: NuGet/setup-nuget@v1.0.5 with: nuget-version: latest - name: Set API key if: github.event_name == 'push' && github.ref == 'refs/heads/main' run: nuget setapikey ${{ secrets.FEEDZ_TOKEN }} -Config nuget.config -Source https://f.feedz.io/davidfowl/ucontroller/nuget/index.json - name: Set symbols API key if: github.event_name == 'push' && github.ref == 'refs/heads/main' run: nuget setapikey ${{ secrets.FEEDZ_TOKEN }} -Config nuget.config -Source https://f.feedz.io/davidfowl/ucontroller/symbols - name: push packages if: github.event_name == 'push' && github.ref == 'refs/heads/main' run: dotnet nuget push **/*.nupkg -s https://f.feedz.io/davidfowl/ucontroller/nuget/index.json -ss https://f.feedz.io/davidfowl/ucontroller/symbols --skip-duplicate ================================================ FILE: .gitignore ================================================ [Oo]bj/ [Bb]in/ TestResults/ .nuget/ *.sln.ide/ _ReSharper.*/ .idea/ packages/ artifacts/ PublishProfiles/ .vs/ *.user *.suo *.cache *.docstates _ReSharper.* nuget.exe *net45.csproj *net451.csproj *k10.csproj *.psess *.vsp *.pidb *.userprefs *DS_Store *.ncrunchsolution *.*sdf *.ipch *.swp *~ .build/ .testPublish/ launchSettings.json BenchmarkDotNet.Artifacts/ BDN.Generated/ binaries/ global.json korebuild-lock.txt ================================================ FILE: .vscode/launch.json ================================================ { // Use IntelliSense to learn about possible attributes. // Hover to view descriptions of existing attributes. // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 "version": "0.2.0", "configurations": [ { "name": ".NET Core Launch (console)", "type": "coreclr", "request": "launch", "preLaunchTask": "build", "program": "${workspaceFolder}/test/uController.SourceGenerator.Tests/bin/Debug/net7.0/uController.SourceGenerator.Tests.dll", "args": [], "cwd": "${workspaceFolder}/test/uController.SourceGenerator.Tests", "console": "internalConsole", "stopAtEntry": false }, { "name": ".NET Core Attach", "type": "coreclr", "request": "attach" } ] } ================================================ FILE: .vscode/settings.json ================================================ { "dotnet.defaultSolution": "uController.sln" } ================================================ FILE: .vscode/tasks.json ================================================ { "version": "2.0.0", "tasks": [ { "label": "build", "command": "dotnet", "type": "process", "args": [ "build", "${workspaceFolder}/test/uController.SourceGenerator.Tests/uController.SourceGenerator.Tests.csproj", "/property:GenerateFullPaths=true", "/consoleloggerparameters:NoSummary" ], "problemMatcher": "$msCompile" }, { "label": "publish", "command": "dotnet", "type": "process", "args": [ "publish", "${workspaceFolder}/test/uController.SourceGenerator.Tests/uController.SourceGenerator.Tests.csproj", "/property:GenerateFullPaths=true", "/consoleloggerparameters:NoSummary" ], "problemMatcher": "$msCompile" }, { "label": "watch", "command": "dotnet", "type": "process", "args": [ "watch", "run", "--project", "${workspaceFolder}/test/uController.SourceGenerator.Tests/uController.SourceGenerator.Tests.csproj" ], "problemMatcher": "$msCompile" } ] } ================================================ FILE: Directory.Build.props ================================================ false $(NoWarn);NU5105 https://github.com/davidfowl/uController https://github.com/davidfowl/uController https://github.com/davidfowl/uController/releases MIT git cloud API REST microservice web ================================================ FILE: GeneratedOutput/RouteBuilderExtensions.g.cs ================================================  //------------------------------------------------------------------------------ // // This code was generated by a tool. // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // //------------------------------------------------------------------------------ #if NET7_0_OR_GREATER using System.Diagnostics; using System.Reflection; using Microsoft.AspNetCore.Routing.Patterns; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.FileProviders; using Microsoft.Extensions.Primitives; using MetadataPopulator = System.Action; using RequestDelegateFactoryFunc = System.Func; namespace Microsoft.AspNetCore.Builder { internal record SourceKey(string Path, int Line); } internal static class GeneratedRouteBuilderExtensions { private static readonly string[] GetVerb = new[] { HttpMethods.Get }; private static readonly string[] PostVerb = new[] { HttpMethods.Post }; private static readonly string[] PutVerb = new[] { HttpMethods.Put }; private static readonly string[] DeleteVerb = new[] { HttpMethods.Delete }; private static readonly string[] PatchVerb = new[] { HttpMethods.Patch }; private class GenericThunks { public static readonly System.Collections.Generic.Dictionary<(string, int), (MetadataPopulator, RequestDelegateFactoryFunc)> map = new() { [(@"C:\dev\git\uController\samples\Program.cs", 19)] = ( (del, builder) => { builder.Metadata.Add(new SourceKey(@"C:\dev\git\uController\samples\Program.cs", 19)); builder.Metadata.Add(ResponseTypeMetadata.Create("application/json", typeof(T))); }, (del, builder) => { var handler = (System.Func)del; EndpointFilterDelegate filteredInvocation = null; if (builder.FilterFactories.Count > 0) { filteredInvocation = BuildFilterDelegate(ic => { if (ic.HttpContext.Response.StatusCode == 400) { return System.Threading.Tasks.ValueTask.FromResult(Results.Empty); } return System.Threading.Tasks.ValueTask.FromResult(handler()); }, builder, handler.Method); } System.Threading.Tasks.Task RequestHandler(Microsoft.AspNetCore.Http.HttpContext httpContext) { var result = handler(); return httpContext.Response.WriteAsJsonAsync(result); } async System.Threading.Tasks.Task RequestHandlerFiltered(Microsoft.AspNetCore.Http.HttpContext httpContext) { var result = await filteredInvocation(new DefaultEndpointFilterInvocationContext(httpContext)); await ExecuteObjectResult(result, httpContext); } return filteredInvocation is null ? RequestHandler : RequestHandlerFiltered; }), }; } private static readonly System.Collections.Generic.Dictionary<(string, int), (MetadataPopulator, RequestDelegateFactoryFunc)> map = new() { [(@"C:\dev\git\uController\samples\MapTodos.cs", 9)] = ( (del, builder) => { builder.Metadata.Add(new SourceKey(@"C:\dev\git\uController\samples\MapTodos.cs", 9)); builder.Metadata.Add(ResponseTypeMetadata.Create("application/json", typeof(System.Collections.Generic.List))); }, (del, builder) => { var handler = (System.Func>>)del; EndpointFilterDelegate filteredInvocation = null; var ispis = builder.ApplicationServices.GetService(); System.Func> arg_dbServiceOrBodyResolver = (ispis?.IsService(typeof(TodoDbContext)) ?? false) ? ResolveService : ResolveBody; if (builder.FilterFactories.Count > 0) { filteredInvocation = BuildFilterDelegate(ic => { if (ic.HttpContext.Response.StatusCode == 400) { return System.Threading.Tasks.ValueTask.FromResult(Results.Empty); } return System.Threading.Tasks.ValueTask.FromResult(handler(ic.GetArgument(0))); }, builder, handler.Method); } async System.Threading.Tasks.Task RequestHandler(Microsoft.AspNetCore.Http.HttpContext httpContext) { var arg_db = await arg_dbServiceOrBodyResolver(httpContext); var result = await handler(arg_db); await httpContext.Response.WriteAsJsonAsync(result); } async System.Threading.Tasks.Task RequestHandlerFiltered(Microsoft.AspNetCore.Http.HttpContext httpContext) { var arg_db = await arg_dbServiceOrBodyResolver(httpContext); var result = await filteredInvocation(new DefaultEndpointFilterInvocationContext(httpContext, arg_db)); await ExecuteObjectResult(result, httpContext); } return filteredInvocation is null ? RequestHandler : RequestHandlerFiltered; }), [(@"C:\dev\git\uController\samples\MapTodos.cs", 17)] = ( (del, builder) => { builder.Metadata.Add(new SourceKey(@"C:\dev\git\uController\samples\MapTodos.cs", 17)); PopulateMetadata>(del.Method, builder); PopulateMetadata(del.Method, builder); }, (del, builder) => { var handler = (System.Func>)del; EndpointFilterDelegate filteredInvocation = null; var ispis = builder.ApplicationServices.GetService(); System.Func> arg_dbServiceOrBodyResolver = (ispis?.IsService(typeof(TodoDbContext)) ?? false) ? ResolveService : ResolveBody; if (builder.FilterFactories.Count > 0) { filteredInvocation = BuildFilterDelegate(ic => { if (ic.HttpContext.Response.StatusCode == 400) { return System.Threading.Tasks.ValueTask.FromResult(Results.Empty); } return System.Threading.Tasks.ValueTask.FromResult(handler(ic.GetArgument(0), ic.GetArgument(1))); }, builder, handler.Method); } async System.Threading.Tasks.Task RequestHandler(Microsoft.AspNetCore.Http.HttpContext httpContext) { var wasParamCheckFailure = false; var arg_id_Value = httpContext.Request.RouteValues["id"]?.ToString(); int arg_id; if (arg_id_Value == null || !int.TryParse(arg_id_Value, out arg_id)) { arg_id = default; wasParamCheckFailure = true; } var arg_db = await arg_dbServiceOrBodyResolver(httpContext); if (wasParamCheckFailure) { httpContext.Response.StatusCode = 400; return; } var result = await handler(arg_id, arg_db); await result.ExecuteAsync(httpContext); } async System.Threading.Tasks.Task RequestHandlerFiltered(Microsoft.AspNetCore.Http.HttpContext httpContext) { var wasParamCheckFailure = false; var arg_id_Value = httpContext.Request.RouteValues["id"]?.ToString(); int arg_id; if (arg_id_Value == null || !int.TryParse(arg_id_Value, out arg_id)) { arg_id = default; wasParamCheckFailure = true; } var arg_db = await arg_dbServiceOrBodyResolver(httpContext); if (wasParamCheckFailure) { httpContext.Response.StatusCode = 400; } var result = await filteredInvocation(new DefaultEndpointFilterInvocationContext(httpContext, arg_id, arg_db)); await ExecuteObjectResult(result, httpContext); } return filteredInvocation is null ? RequestHandler : RequestHandlerFiltered; }), [(@"C:\dev\git\uController\samples\MapTodos.cs", 29)] = ( (del, builder) => { builder.Metadata.Add(new SourceKey(@"C:\dev\git\uController\samples\MapTodos.cs", 29)); PopulateMetadata(del.Method, builder); PopulateMetadata(del.Method, builder); }, (del, builder) => { var handler = (System.Func>)del; EndpointFilterDelegate filteredInvocation = null; var ispis = builder.ApplicationServices.GetService(); System.Func> arg_todoServiceOrBodyResolver = (ispis?.IsService(typeof(Todo)) ?? false) ? ResolveService : ResolveBody; System.Func> arg_dbServiceOrBodyResolver = (ispis?.IsService(typeof(TodoDbContext)) ?? false) ? ResolveService : ResolveBody; if (builder.FilterFactories.Count > 0) { filteredInvocation = BuildFilterDelegate(ic => { if (ic.HttpContext.Response.StatusCode == 400) { return System.Threading.Tasks.ValueTask.FromResult(Results.Empty); } return System.Threading.Tasks.ValueTask.FromResult(handler(ic.GetArgument(0), ic.GetArgument(1), ic.GetArgument(2))); }, builder, handler.Method); } async System.Threading.Tasks.Task RequestHandler(Microsoft.AspNetCore.Http.HttpContext httpContext) { var wasParamCheckFailure = false; var arg_id_Value = httpContext.Request.RouteValues["id"]?.ToString(); int arg_id; if (arg_id_Value == null || !int.TryParse(arg_id_Value, out arg_id)) { arg_id = default; wasParamCheckFailure = true; } var arg_todo = await arg_todoServiceOrBodyResolver(httpContext); var arg_db = await arg_dbServiceOrBodyResolver(httpContext); if (wasParamCheckFailure) { httpContext.Response.StatusCode = 400; return; } var result = await handler(arg_id, arg_todo, arg_db); await result.ExecuteAsync(httpContext); } async System.Threading.Tasks.Task RequestHandlerFiltered(Microsoft.AspNetCore.Http.HttpContext httpContext) { var wasParamCheckFailure = false; var arg_id_Value = httpContext.Request.RouteValues["id"]?.ToString(); int arg_id; if (arg_id_Value == null || !int.TryParse(arg_id_Value, out arg_id)) { arg_id = default; wasParamCheckFailure = true; } var arg_todo = await arg_todoServiceOrBodyResolver(httpContext); var arg_db = await arg_dbServiceOrBodyResolver(httpContext); if (wasParamCheckFailure) { httpContext.Response.StatusCode = 400; } var result = await filteredInvocation(new DefaultEndpointFilterInvocationContext(httpContext, arg_id, arg_todo, arg_db)); await ExecuteObjectResult(result, httpContext); } return filteredInvocation is null ? RequestHandler : RequestHandlerFiltered; }), [(@"C:\dev\git\uController\samples\MapTodos.cs", 48)] = ( (del, builder) => { builder.Metadata.Add(new SourceKey(@"C:\dev\git\uController\samples\MapTodos.cs", 48)); PopulateMetadata>(del.Method, builder); }, (del, builder) => { var handler = (System.Func>)del; EndpointFilterDelegate filteredInvocation = null; var ispis = builder.ApplicationServices.GetService(); System.Func> arg_todoServiceOrBodyResolver = (ispis?.IsService(typeof(Todo)) ?? false) ? ResolveService : ResolveBody; System.Func> arg_dbServiceOrBodyResolver = (ispis?.IsService(typeof(TodoDbContext)) ?? false) ? ResolveService : ResolveBody; if (builder.FilterFactories.Count > 0) { filteredInvocation = BuildFilterDelegate(ic => { if (ic.HttpContext.Response.StatusCode == 400) { return System.Threading.Tasks.ValueTask.FromResult(Results.Empty); } return System.Threading.Tasks.ValueTask.FromResult(handler(ic.GetArgument(0), ic.GetArgument(1))); }, builder, handler.Method); } async System.Threading.Tasks.Task RequestHandler(Microsoft.AspNetCore.Http.HttpContext httpContext) { var arg_todo = await arg_todoServiceOrBodyResolver(httpContext); var arg_db = await arg_dbServiceOrBodyResolver(httpContext); var result = await handler(arg_todo, arg_db); await result.ExecuteAsync(httpContext); } async System.Threading.Tasks.Task RequestHandlerFiltered(Microsoft.AspNetCore.Http.HttpContext httpContext) { var arg_todo = await arg_todoServiceOrBodyResolver(httpContext); var arg_db = await arg_dbServiceOrBodyResolver(httpContext); var result = await filteredInvocation(new DefaultEndpointFilterInvocationContext(httpContext, arg_todo, arg_db)); await ExecuteObjectResult(result, httpContext); } return filteredInvocation is null ? RequestHandler : RequestHandlerFiltered; }), [(@"C:\dev\git\uController\samples\MapTodos.cs", 58)] = ( (del, builder) => { builder.Metadata.Add(new SourceKey(@"C:\dev\git\uController\samples\MapTodos.cs", 58)); PopulateMetadata>(del.Method, builder); PopulateMetadata(del.Method, builder); }, (del, builder) => { var handler = (System.Func>)del; EndpointFilterDelegate filteredInvocation = null; var ispis = builder.ApplicationServices.GetService(); System.Func> arg_dbServiceOrBodyResolver = (ispis?.IsService(typeof(TodoDbContext)) ?? false) ? ResolveService : ResolveBody; if (builder.FilterFactories.Count > 0) { filteredInvocation = BuildFilterDelegate(ic => { if (ic.HttpContext.Response.StatusCode == 400) { return System.Threading.Tasks.ValueTask.FromResult(Results.Empty); } return System.Threading.Tasks.ValueTask.FromResult(handler(ic.GetArgument(0), ic.GetArgument(1))); }, builder, handler.Method); } async System.Threading.Tasks.Task RequestHandler(Microsoft.AspNetCore.Http.HttpContext httpContext) { var wasParamCheckFailure = false; var arg_id_Value = httpContext.Request.RouteValues["id"]?.ToString(); int arg_id; if (arg_id_Value == null || !int.TryParse(arg_id_Value, out arg_id)) { arg_id = default; wasParamCheckFailure = true; } var arg_db = await arg_dbServiceOrBodyResolver(httpContext); if (wasParamCheckFailure) { httpContext.Response.StatusCode = 400; return; } var result = await handler(arg_id, arg_db); await result.ExecuteAsync(httpContext); } async System.Threading.Tasks.Task RequestHandlerFiltered(Microsoft.AspNetCore.Http.HttpContext httpContext) { var wasParamCheckFailure = false; var arg_id_Value = httpContext.Request.RouteValues["id"]?.ToString(); int arg_id; if (arg_id_Value == null || !int.TryParse(arg_id_Value, out arg_id)) { arg_id = default; wasParamCheckFailure = true; } var arg_db = await arg_dbServiceOrBodyResolver(httpContext); if (wasParamCheckFailure) { httpContext.Response.StatusCode = 400; } var result = await filteredInvocation(new DefaultEndpointFilterInvocationContext(httpContext, arg_id, arg_db)); await ExecuteObjectResult(result, httpContext); } return filteredInvocation is null ? RequestHandler : RequestHandlerFiltered; }), [(@"C:\dev\git\uController\samples\Program.cs", 16)] = ( (del, builder) => { builder.Metadata.Add(new SourceKey(@"C:\dev\git\uController\samples\Program.cs", 16)); builder.Metadata.Add(ResponseTypeMetadata.Create("text/plain")); }, (del, builder) => { var handler = (System.Func)del; EndpointFilterDelegate filteredInvocation = null; if (builder.FilterFactories.Count > 0) { filteredInvocation = BuildFilterDelegate(ic => { if (ic.HttpContext.Response.StatusCode == 400) { return System.Threading.Tasks.ValueTask.FromResult(Results.Empty); } return System.Threading.Tasks.ValueTask.FromResult(handler()); }, builder, handler.Method); } System.Threading.Tasks.Task RequestHandler(Microsoft.AspNetCore.Http.HttpContext httpContext) { var result = handler(); return httpContext.Response.WriteAsync(result); } async System.Threading.Tasks.Task RequestHandlerFiltered(Microsoft.AspNetCore.Http.HttpContext httpContext) { var result = await filteredInvocation(new DefaultEndpointFilterInvocationContext(httpContext)); await ExecuteObjectResult(result, httpContext); } return filteredInvocation is null ? RequestHandler : RequestHandlerFiltered; }), [(@"C:\dev\git\uController\samples\Program.cs", 17)] = ( (del, builder) => { builder.Metadata.Add(new SourceKey(@"C:\dev\git\uController\samples\Program.cs", 17)); builder.Metadata.Add(ResponseTypeMetadata.Create("text/plain")); }, (del, builder) => { var handler = (System.Func)del; EndpointFilterDelegate filteredInvocation = null; if (builder.FilterFactories.Count > 0) { filteredInvocation = BuildFilterDelegate(ic => { if (ic.HttpContext.Response.StatusCode == 400) { return System.Threading.Tasks.ValueTask.FromResult(Results.Empty); } return System.Threading.Tasks.ValueTask.FromResult(handler(ic.GetArgument(0))); }, builder, handler.Method); } System.Threading.Tasks.Task RequestHandler(Microsoft.AspNetCore.Http.HttpContext httpContext) { var arg_name = httpContext.Request.RouteValues["name"]?.ToString(); var result = handler(arg_name); return httpContext.Response.WriteAsync(result); } async System.Threading.Tasks.Task RequestHandlerFiltered(Microsoft.AspNetCore.Http.HttpContext httpContext) { var arg_name = httpContext.Request.RouteValues["name"]?.ToString(); var result = await filteredInvocation(new DefaultEndpointFilterInvocationContext(httpContext, arg_name)); await ExecuteObjectResult(result, httpContext); } return filteredInvocation is null ? RequestHandler : RequestHandlerFiltered; }), [(@"C:\dev\git\uController\samples\Program.cs", 21)] = ( (del, builder) => { builder.Metadata.Add(new SourceKey(@"C:\dev\git\uController\samples\Program.cs", 21)); builder.Metadata.Add(ResponseTypeMetadata.Create("application/json", typeof(Person))); }, (del, builder) => { var handler = (System.Func)del; EndpointFilterDelegate filteredInvocation = null; if (builder.FilterFactories.Count > 0) { filteredInvocation = BuildFilterDelegate(ic => { if (ic.HttpContext.Response.StatusCode == 400) { return System.Threading.Tasks.ValueTask.FromResult(Results.Empty); } return System.Threading.Tasks.ValueTask.FromResult(handler()); }, builder, handler.Method); } System.Threading.Tasks.Task RequestHandler(Microsoft.AspNetCore.Http.HttpContext httpContext) { var result = handler(); return httpContext.Response.WriteAsJsonAsync(result); } async System.Threading.Tasks.Task RequestHandlerFiltered(Microsoft.AspNetCore.Http.HttpContext httpContext) { var result = await filteredInvocation(new DefaultEndpointFilterInvocationContext(httpContext)); await ExecuteObjectResult(result, httpContext); } return filteredInvocation is null ? RequestHandler : RequestHandlerFiltered; }), [(@"C:\dev\git\uController\samples\Program.cs", 23)] = ( (del, builder) => { builder.Metadata.Add(new SourceKey(@"C:\dev\git\uController\samples\Program.cs", 23)); PopulateMetadata>(del.Method, builder); }, (del, builder) => { var handler = (System.Func)del; EndpointFilterDelegate filteredInvocation = null; var ispis = builder.ApplicationServices.GetService(); System.Func> arg_hellosvcServiceOrBodyResolver = (ispis?.IsService(typeof(ISayHello)) ?? false) ? ResolveService : ResolveBody; if (builder.FilterFactories.Count > 0) { filteredInvocation = BuildFilterDelegate(ic => { if (ic.HttpContext.Response.StatusCode == 400) { return System.Threading.Tasks.ValueTask.FromResult(Results.Empty); } return System.Threading.Tasks.ValueTask.FromResult(handler(ic.GetArgument(0), ic.GetArgument(1))); }, builder, handler.Method); } async System.Threading.Tasks.Task RequestHandler(Microsoft.AspNetCore.Http.HttpContext httpContext) { var arg_c = httpContext.User; var arg_hellosvc = await arg_hellosvcServiceOrBodyResolver(httpContext); var result = handler(arg_c, arg_hellosvc); await result.ExecuteAsync(httpContext); } async System.Threading.Tasks.Task RequestHandlerFiltered(Microsoft.AspNetCore.Http.HttpContext httpContext) { var arg_c = httpContext.User; var arg_hellosvc = await arg_hellosvcServiceOrBodyResolver(httpContext); var result = await filteredInvocation(new DefaultEndpointFilterInvocationContext(httpContext, arg_c, arg_hellosvc)); await ExecuteObjectResult(result, httpContext); } return filteredInvocation is null ? RequestHandler : RequestHandlerFiltered; }), [(@"C:\dev\git\uController\samples\Program.cs", 25)] = ( (del, builder) => { builder.Metadata.Add(new SourceKey(@"C:\dev\git\uController\samples\Program.cs", 25)); builder.Metadata.Add(ResponseTypeMetadata.Create("application/json", typeof(System.Text.Json.Nodes.JsonNode))); }, (del, builder) => { var handler = (System.Func)del; EndpointFilterDelegate filteredInvocation = null; var ispis = builder.ApplicationServices.GetService(); System.Func> arg_nodeServiceOrBodyResolver = (ispis?.IsService(typeof(System.Text.Json.Nodes.JsonNode)) ?? false) ? ResolveService : ResolveBody; if (builder.FilterFactories.Count > 0) { filteredInvocation = BuildFilterDelegate(ic => { if (ic.HttpContext.Response.StatusCode == 400) { return System.Threading.Tasks.ValueTask.FromResult(Results.Empty); } return System.Threading.Tasks.ValueTask.FromResult(handler(ic.GetArgument(0))); }, builder, handler.Method); } async System.Threading.Tasks.Task RequestHandler(Microsoft.AspNetCore.Http.HttpContext httpContext) { var arg_node = await arg_nodeServiceOrBodyResolver(httpContext); var result = handler(arg_node); await httpContext.Response.WriteAsJsonAsync(result); } async System.Threading.Tasks.Task RequestHandlerFiltered(Microsoft.AspNetCore.Http.HttpContext httpContext) { var arg_node = await arg_nodeServiceOrBodyResolver(httpContext); var result = await filteredInvocation(new DefaultEndpointFilterInvocationContext(httpContext, arg_node)); await ExecuteObjectResult(result, httpContext); } return filteredInvocation is null ? RequestHandler : RequestHandlerFiltered; }), [(@"C:\dev\git\uController\samples\Program.cs", 26)] = ( (del, builder) => { builder.Metadata.Add(new SourceKey(@"C:\dev\git\uController\samples\Program.cs", 26)); builder.Metadata.Add(ResponseTypeMetadata.Create("application/json", typeof(System.Text.Json.Nodes.JsonNode))); }, (del, builder) => { var handler = (System.Func)del; EndpointFilterDelegate filteredInvocation = null; if (builder.FilterFactories.Count > 0) { filteredInvocation = BuildFilterDelegate(ic => { if (ic.HttpContext.Response.StatusCode == 400) { return System.Threading.Tasks.ValueTask.FromResult(Results.Empty); } return System.Threading.Tasks.ValueTask.FromResult(handler(ic.GetArgument(0))); }, builder, handler.Method); } async System.Threading.Tasks.Task RequestHandler(Microsoft.AspNetCore.Http.HttpContext httpContext) { var arg_node = await ResolveBody(httpContext); var result = handler(arg_node); await httpContext.Response.WriteAsJsonAsync(result); } async System.Threading.Tasks.Task RequestHandlerFiltered(Microsoft.AspNetCore.Http.HttpContext httpContext) { var arg_node = await ResolveBody(httpContext); var result = await filteredInvocation(new DefaultEndpointFilterInvocationContext(httpContext, arg_node)); await ExecuteObjectResult(result, httpContext); } return filteredInvocation is null ? RequestHandler : RequestHandlerFiltered; }), [(@"C:\dev\git\uController\samples\Program.cs", 28)] = ( (del, builder) => { builder.Metadata.Add(new SourceKey(@"C:\dev\git\uController\samples\Program.cs", 28)); builder.Metadata.Add(ResponseTypeMetadata.Create("application/json", typeof(Model))); }, (del, builder) => { var handler = (System.Func)del; EndpointFilterDelegate filteredInvocation = null; var parameterInfos = del.Method.GetParameters(); var arg_mParameterInfo = parameterInfos[0]; if (builder.FilterFactories.Count > 0) { filteredInvocation = BuildFilterDelegate(ic => { if (ic.HttpContext.Response.StatusCode == 400) { return System.Threading.Tasks.ValueTask.FromResult(Results.Empty); } return System.Threading.Tasks.ValueTask.FromResult(handler(ic.GetArgument(0))); }, builder, handler.Method); } async System.Threading.Tasks.Task RequestHandler(Microsoft.AspNetCore.Http.HttpContext httpContext) { var arg_m = await Model.BindAsync(httpContext, arg_mParameterInfo); var result = handler(arg_m); await httpContext.Response.WriteAsJsonAsync(result); } async System.Threading.Tasks.Task RequestHandlerFiltered(Microsoft.AspNetCore.Http.HttpContext httpContext) { var arg_m = await Model.BindAsync(httpContext, arg_mParameterInfo); var result = await filteredInvocation(new DefaultEndpointFilterInvocationContext(httpContext, arg_m)); await ExecuteObjectResult(result, httpContext); } return filteredInvocation is null ? RequestHandler : RequestHandlerFiltered; }), [(@"C:\dev\git\uController\samples\Program.cs", 29)] = ( (del, builder) => { builder.Metadata.Add(new SourceKey(@"C:\dev\git\uController\samples\Program.cs", 29)); }, (del, builder) => { var handler = (System.Action)del; EndpointFilterDelegate filteredInvocation = null; var parameterInfos = del.Method.GetParameters(); var arg_mParameterInfo = parameterInfos[0]; if (builder.FilterFactories.Count > 0) { filteredInvocation = BuildFilterDelegate(ic => { if (ic.HttpContext.Response.StatusCode == 400) { return System.Threading.Tasks.ValueTask.FromResult(Results.Empty); } handler(ic.GetArgument(0)); return System.Threading.Tasks.ValueTask.FromResult(Results.Empty); }, builder, handler.Method); } async System.Threading.Tasks.Task RequestHandler(Microsoft.AspNetCore.Http.HttpContext httpContext) { var arg_m = await Model.BindAsync(httpContext, arg_mParameterInfo); handler(arg_m); } async System.Threading.Tasks.Task RequestHandlerFiltered(Microsoft.AspNetCore.Http.HttpContext httpContext) { var arg_m = await Model.BindAsync(httpContext, arg_mParameterInfo); var result = await filteredInvocation(new DefaultEndpointFilterInvocationContext(httpContext, arg_m)); await ExecuteObjectResult(result, httpContext); } return filteredInvocation is null ? RequestHandler : RequestHandlerFiltered; }), [(@"C:\dev\git\uController\samples\Program.cs", 31)] = ( (del, builder) => { builder.Metadata.Add(new SourceKey(@"C:\dev\git\uController\samples\Program.cs", 31)); builder.Metadata.Add(ResponseTypeMetadata.Create("text/plain")); }, (del, builder) => { var handler = (System.Func)del; EndpointFilterDelegate filteredInvocation = null; if (builder.FilterFactories.Count > 0) { filteredInvocation = BuildFilterDelegate(ic => { if (ic.HttpContext.Response.StatusCode == 400) { return System.Threading.Tasks.ValueTask.FromResult(Results.Empty); } return System.Threading.Tasks.ValueTask.FromResult(handler(ic.GetArgument(0))); }, builder, handler.Method); } async System.Threading.Tasks.Task RequestHandler(Microsoft.AspNetCore.Http.HttpContext httpContext) { var formCollection = await httpContext.Request.ReadFormAsync(); var arg_file = formCollection.Files["file"]; var result = handler(arg_file); await httpContext.Response.WriteAsync(result); } async System.Threading.Tasks.Task RequestHandlerFiltered(Microsoft.AspNetCore.Http.HttpContext httpContext) { var formCollection = await httpContext.Request.ReadFormAsync(); var arg_file = formCollection.Files["file"]; var result = await filteredInvocation(new DefaultEndpointFilterInvocationContext(httpContext, arg_file)); await ExecuteObjectResult(result, httpContext); } return filteredInvocation is null ? RequestHandler : RequestHandlerFiltered; }), [(@"C:\dev\git\uController\samples\Program.cs", 36)] = ( (del, builder) => { builder.Metadata.Add(new SourceKey(@"C:\dev\git\uController\samples\Program.cs", 36)); PopulateMetadata(del.Method, builder); PopulateMetadata>(del.Method, builder); }, (del, builder) => { var handler = (System.Func)del; EndpointFilterDelegate filteredInvocation = null; var routePattern = (builder as RouteEndpointBuilder)?.RoutePattern; System.Func arg_nameRouteOrQueryResolver = routePattern?.GetParameter("name") is null ? ResolveByQuery : ResolveByRoute; if (builder.FilterFactories.Count > 0) { filteredInvocation = BuildFilterDelegate(ic => { if (ic.HttpContext.Response.StatusCode == 400) { return System.Threading.Tasks.ValueTask.FromResult(Results.Empty); } return System.Threading.Tasks.ValueTask.FromResult(handler(ic.GetArgument(0))); }, builder, handler.Method); } System.Threading.Tasks.Task RequestHandler(Microsoft.AspNetCore.Http.HttpContext httpContext) { var arg_name = arg_nameRouteOrQueryResolver(httpContext, "name").ToString(); var result = handler(arg_name); return result.ExecuteAsync(httpContext); } async System.Threading.Tasks.Task RequestHandlerFiltered(Microsoft.AspNetCore.Http.HttpContext httpContext) { var arg_name = arg_nameRouteOrQueryResolver(httpContext, "name").ToString(); var result = await filteredInvocation(new DefaultEndpointFilterInvocationContext(httpContext, arg_name)); await ExecuteObjectResult(result, httpContext); } return filteredInvocation is null ? RequestHandler : RequestHandlerFiltered; }), [(@"C:\dev\git\uController\samples\Program.cs", 39)] = ( (del, builder) => { builder.Metadata.Add(new SourceKey(@"C:\dev\git\uController\samples\Program.cs", 39)); builder.Metadata.Add(ResponseTypeMetadata.Create("text/plain")); }, (del, builder) => { var handler = (System.Func)del; EndpointFilterDelegate filteredInvocation = null; if (builder.FilterFactories.Count > 0) { filteredInvocation = BuildFilterDelegate(ic => { if (ic.HttpContext.Response.StatusCode == 400) { return System.Threading.Tasks.ValueTask.FromResult(Results.Empty); } return System.Threading.Tasks.ValueTask.FromResult(handler(ic.GetArgument(0))); }, builder, handler.Method); } async System.Threading.Tasks.Task RequestHandler(Microsoft.AspNetCore.Http.HttpContext httpContext) { var formCollection = await httpContext.Request.ReadFormAsync(); var arg_formCollection = formCollection; var result = handler(arg_formCollection); await httpContext.Response.WriteAsync(result); } async System.Threading.Tasks.Task RequestHandlerFiltered(Microsoft.AspNetCore.Http.HttpContext httpContext) { var formCollection = await httpContext.Request.ReadFormAsync(); var arg_formCollection = formCollection; var result = await filteredInvocation(new DefaultEndpointFilterInvocationContext(httpContext, arg_formCollection)); await ExecuteObjectResult(result, httpContext); } return filteredInvocation is null ? RequestHandler : RequestHandlerFiltered; }), [(@"C:\dev\git\uController\samples\Program.cs", 44)] = ( (del, builder) => { var parameterInfos = del.Method.GetParameters(); PopulateMetadata>(parameterInfos[0], builder); builder.Metadata.Add(new SourceKey(@"C:\dev\git\uController\samples\Program.cs", 44)); builder.Metadata.Add(ResponseTypeMetadata.Create("text/plain")); }, (del, builder) => { var handler = (System.Func, string>)del; EndpointFilterDelegate filteredInvocation = null; var parameterInfos = del.Method.GetParameters(); var arg_bodyParameterInfo = parameterInfos[0]; if (builder.FilterFactories.Count > 0) { filteredInvocation = BuildFilterDelegate(ic => { if (ic.HttpContext.Response.StatusCode == 400) { return System.Threading.Tasks.ValueTask.FromResult(Results.Empty); } return System.Threading.Tasks.ValueTask.FromResult(handler(ic.GetArgument>(0))); }, builder, handler.Method); } async System.Threading.Tasks.Task RequestHandler(Microsoft.AspNetCore.Http.HttpContext httpContext) { var arg_body = await MinimalApis.Extensions.Binding.Body.BindAsync(httpContext, arg_bodyParameterInfo); var result = handler(arg_body); await httpContext.Response.WriteAsync(result); } async System.Threading.Tasks.Task RequestHandlerFiltered(Microsoft.AspNetCore.Http.HttpContext httpContext) { var arg_body = await MinimalApis.Extensions.Binding.Body.BindAsync(httpContext, arg_bodyParameterInfo); var result = await filteredInvocation(new DefaultEndpointFilterInvocationContext(httpContext, arg_body)); await ExecuteObjectResult(result, httpContext); } return filteredInvocation is null ? RequestHandler : RequestHandlerFiltered; }), [(@"C:\dev\git\uController\samples\Program.cs", 46)] = ( (del, builder) => { var parameterInfos = del.Method.GetParameters(); PopulateMetadata>(parameterInfos[0], builder); builder.Metadata.Add(new SourceKey(@"C:\dev\git\uController\samples\Program.cs", 46)); PopulateMetadata(del.Method, builder); PopulateMetadata(del.Method, builder); }, (del, builder) => { var handler = (System.Func, Microsoft.AspNetCore.Http.IResult>)del; EndpointFilterDelegate filteredInvocation = null; var parameterInfos = del.Method.GetParameters(); var arg_modelParameterInfo = parameterInfos[0]; if (builder.FilterFactories.Count > 0) { filteredInvocation = BuildFilterDelegate(ic => { if (ic.HttpContext.Response.StatusCode == 400) { return System.Threading.Tasks.ValueTask.FromResult(Results.Empty); } return System.Threading.Tasks.ValueTask.FromResult(handler(ic.GetArgument>(0))); }, builder, handler.Method); } async System.Threading.Tasks.Task RequestHandler(Microsoft.AspNetCore.Http.HttpContext httpContext) { var arg_model = await MinimalApis.Extensions.Binding.Validated.BindAsync(httpContext, arg_modelParameterInfo); var result = handler(arg_model); await result.ExecuteAsync(httpContext); } async System.Threading.Tasks.Task RequestHandlerFiltered(Microsoft.AspNetCore.Http.HttpContext httpContext) { var arg_model = await MinimalApis.Extensions.Binding.Validated.BindAsync(httpContext, arg_modelParameterInfo); var result = await filteredInvocation(new DefaultEndpointFilterInvocationContext(httpContext, arg_model)); await ExecuteObjectResult(result, httpContext); } return filteredInvocation is null ? RequestHandler : RequestHandlerFiltered; }), [(@"C:\dev\git\uController\samples\Program.cs", 55)] = ( (del, builder) => { builder.Metadata.Add(new SourceKey(@"C:\dev\git\uController\samples\Program.cs", 55)); builder.Metadata.Add(ResponseTypeMetadata.Create("application/json", typeof(object))); }, (del, builder) => { var handler = (System.Func)del; EndpointFilterDelegate filteredInvocation = null; if (builder.FilterFactories.Count > 0) { filteredInvocation = BuildFilterDelegate(ic => { if (ic.HttpContext.Response.StatusCode == 400) { return System.Threading.Tasks.ValueTask.FromResult(Results.Empty); } return System.Threading.Tasks.ValueTask.FromResult(handler(ic.GetArgument(0))); }, builder, handler.Method); } System.Threading.Tasks.Task RequestHandler(Microsoft.AspNetCore.Http.HttpContext httpContext) { var arg_ct = httpContext.RequestAborted; var result = handler(arg_ct); return ExecuteObjectResult(result, httpContext); } async System.Threading.Tasks.Task RequestHandlerFiltered(Microsoft.AspNetCore.Http.HttpContext httpContext) { var arg_ct = httpContext.RequestAborted; var result = await filteredInvocation(new DefaultEndpointFilterInvocationContext(httpContext, arg_ct)); await ExecuteObjectResult(result, httpContext); } return filteredInvocation is null ? RequestHandler : RequestHandlerFiltered; }), [(@"C:\dev\git\uController\samples\Program.cs", 59)] = ( (del, builder) => { builder.Metadata.Add(new SourceKey(@"C:\dev\git\uController\samples\Program.cs", 59)); builder.Metadata.Add(ResponseTypeMetadata.Create(401)); }, (del, builder) => { var handler = (System.Func)del; EndpointFilterDelegate filteredInvocation = null; var routePattern = (builder as RouteEndpointBuilder)?.RoutePattern; System.Func arg_idRouteOrQueryResolver = routePattern?.GetParameter("id") is null ? ResolveByQuery : ResolveByRoute; if (builder.FilterFactories.Count > 0) { filteredInvocation = BuildFilterDelegate(ic => { if (ic.HttpContext.Response.StatusCode == 400) { return System.Threading.Tasks.ValueTask.FromResult(Results.Empty); } return System.Threading.Tasks.ValueTask.FromResult(handler(ic.GetArgument(0))); }, builder, handler.Method); } System.Threading.Tasks.Task RequestHandler(Microsoft.AspNetCore.Http.HttpContext httpContext) { var arg_id_Value = arg_idRouteOrQueryResolver(httpContext, "id").ToString(); int? arg_id; if (arg_id_Value != null && int.TryParse(arg_id_Value, out var arg_id_Temp)) { arg_id = arg_id_Temp; } else { arg_id = default; } var result = handler(arg_id); return result.ExecuteAsync(httpContext); } async System.Threading.Tasks.Task RequestHandlerFiltered(Microsoft.AspNetCore.Http.HttpContext httpContext) { var arg_id_Value = arg_idRouteOrQueryResolver(httpContext, "id").ToString(); int? arg_id; if (arg_id_Value != null && int.TryParse(arg_id_Value, out var arg_id_Temp)) { arg_id = arg_id_Temp; } else { arg_id = default; } var result = await filteredInvocation(new DefaultEndpointFilterInvocationContext(httpContext, arg_id)); await ExecuteObjectResult(result, httpContext); } return filteredInvocation is null ? RequestHandler : RequestHandlerFiltered; }), [(@"C:\dev\git\uController\samples\Program.cs", 61)] = ( (del, builder) => { builder.Metadata.Add(new SourceKey(@"C:\dev\git\uController\samples\Program.cs", 61)); }, (del, builder) => { var handler = (System.Func)del; EndpointFilterDelegate filteredInvocation = null; if (builder.FilterFactories.Count > 0) { filteredInvocation = BuildFilterDelegate(ic => { if (ic.HttpContext.Response.StatusCode == 400) { return System.Threading.Tasks.ValueTask.FromResult(Results.Empty); } return System.Threading.Tasks.ValueTask.FromResult(handler(ic.GetArgument(0))); }, builder, handler.Method); } System.Threading.Tasks.Task RequestHandler(Microsoft.AspNetCore.Http.HttpContext httpContext) { var arg_s = httpContext.Request.Body; var result = handler(arg_s); return result.ExecuteAsync(httpContext); } async System.Threading.Tasks.Task RequestHandlerFiltered(Microsoft.AspNetCore.Http.HttpContext httpContext) { var arg_s = httpContext.Request.Body; var result = await filteredInvocation(new DefaultEndpointFilterInvocationContext(httpContext, arg_s)); await ExecuteObjectResult(result, httpContext); } return filteredInvocation is null ? RequestHandler : RequestHandlerFiltered; }), [(@"C:\dev\git\uController\samples\Program.cs", 62)] = ( (del, builder) => { builder.Metadata.Add(new SourceKey(@"C:\dev\git\uController\samples\Program.cs", 62)); }, (del, builder) => { var handler = (System.Func)del; EndpointFilterDelegate filteredInvocation = null; if (builder.FilterFactories.Count > 0) { filteredInvocation = BuildFilterDelegate(ic => { if (ic.HttpContext.Response.StatusCode == 400) { return System.Threading.Tasks.ValueTask.FromResult(Results.Empty); } return System.Threading.Tasks.ValueTask.FromResult(handler(ic.GetArgument(0))); }, builder, handler.Method); } System.Threading.Tasks.Task RequestHandler(Microsoft.AspNetCore.Http.HttpContext httpContext) { var arg_r = httpContext.Request.BodyReader; var result = handler(arg_r); return result.ExecuteAsync(httpContext); } async System.Threading.Tasks.Task RequestHandlerFiltered(Microsoft.AspNetCore.Http.HttpContext httpContext) { var arg_r = httpContext.Request.BodyReader; var result = await filteredInvocation(new DefaultEndpointFilterInvocationContext(httpContext, arg_r)); await ExecuteObjectResult(result, httpContext); } return filteredInvocation is null ? RequestHandler : RequestHandlerFiltered; }), [(@"C:\dev\git\uController\samples\Program.cs", 64)] = ( (del, builder) => { builder.Metadata.Add(new SourceKey(@"C:\dev\git\uController\samples\Program.cs", 64)); }, (del, builder) => { var handler = (System.Func)del; EndpointFilterDelegate filteredInvocation = null; if (builder.FilterFactories.Count > 0) { filteredInvocation = BuildFilterDelegate(ic => { if (ic.HttpContext.Response.StatusCode == 400) { return System.Threading.Tasks.ValueTask.FromResult(Results.Empty); } return System.Threading.Tasks.ValueTask.FromResult(handler(ic.GetArgument(0), ic.GetArgument(1))); }, builder, handler.Method); } System.Threading.Tasks.Task RequestHandler(Microsoft.AspNetCore.Http.HttpContext httpContext) { var arg_req = httpContext.Request; var arg_resp = httpContext.Response; return handler(arg_req, arg_resp); } async System.Threading.Tasks.Task RequestHandlerFiltered(Microsoft.AspNetCore.Http.HttpContext httpContext) { var arg_req = httpContext.Request; var arg_resp = httpContext.Response; var result = await filteredInvocation(new DefaultEndpointFilterInvocationContext(httpContext, arg_req, arg_resp)); await ExecuteObjectResult(result, httpContext); } return filteredInvocation is null ? RequestHandler : RequestHandlerFiltered; }), [(@"C:\dev\git\uController\samples\Program.cs", 66)] = ( (del, builder) => { builder.Metadata.Add(new SourceKey(@"C:\dev\git\uController\samples\Program.cs", 66)); builder.Metadata.Add(ResponseTypeMetadata.Create("application/json", typeof(string?[]))); }, (del, builder) => { var handler = (System.Func)del; EndpointFilterDelegate filteredInvocation = null; var routePattern = (builder as RouteEndpointBuilder)?.RoutePattern; System.Func arg_queriesRouteOrQueryResolver = routePattern?.GetParameter("queries") is null ? ResolveByQuery : ResolveByRoute; if (builder.FilterFactories.Count > 0) { filteredInvocation = BuildFilterDelegate(ic => { if (ic.HttpContext.Response.StatusCode == 400) { return System.Threading.Tasks.ValueTask.FromResult(Results.Empty); } return System.Threading.Tasks.ValueTask.FromResult(handler(ic.GetArgument(0))); }, builder, handler.Method); } System.Threading.Tasks.Task RequestHandler(Microsoft.AspNetCore.Http.HttpContext httpContext) { var arg_queries = arg_queriesRouteOrQueryResolver(httpContext, "queries"); var result = handler(arg_queries); return httpContext.Response.WriteAsJsonAsync(result); } async System.Threading.Tasks.Task RequestHandlerFiltered(Microsoft.AspNetCore.Http.HttpContext httpContext) { var arg_queries = arg_queriesRouteOrQueryResolver(httpContext, "queries"); var result = await filteredInvocation(new DefaultEndpointFilterInvocationContext(httpContext, arg_queries)); await ExecuteObjectResult(result, httpContext); } return filteredInvocation is null ? RequestHandler : RequestHandlerFiltered; }), [(@"C:\dev\git\uController\samples\Program.cs", 67)] = ( (del, builder) => { builder.Metadata.Add(new SourceKey(@"C:\dev\git\uController\samples\Program.cs", 67)); builder.Metadata.Add(ResponseTypeMetadata.Create("application/json", typeof(string[]))); }, (del, builder) => { var handler = (System.Func)del; EndpointFilterDelegate filteredInvocation = null; var routePattern = (builder as RouteEndpointBuilder)?.RoutePattern; System.Func arg_queriesRouteOrQueryResolver = routePattern?.GetParameter("queries") is null ? ResolveByQuery : ResolveByRoute; if (builder.FilterFactories.Count > 0) { filteredInvocation = BuildFilterDelegate(ic => { if (ic.HttpContext.Response.StatusCode == 400) { return System.Threading.Tasks.ValueTask.FromResult(Results.Empty); } return System.Threading.Tasks.ValueTask.FromResult(handler(ic.GetArgument(0))); }, builder, handler.Method); } System.Threading.Tasks.Task RequestHandler(Microsoft.AspNetCore.Http.HttpContext httpContext) { var arg_queries = arg_queriesRouteOrQueryResolver(httpContext, "queries").ToArray(); var result = handler(arg_queries); return httpContext.Response.WriteAsJsonAsync(result); } async System.Threading.Tasks.Task RequestHandlerFiltered(Microsoft.AspNetCore.Http.HttpContext httpContext) { var arg_queries = arg_queriesRouteOrQueryResolver(httpContext, "queries").ToArray(); var result = await filteredInvocation(new DefaultEndpointFilterInvocationContext(httpContext, arg_queries)); await ExecuteObjectResult(result, httpContext); } return filteredInvocation is null ? RequestHandler : RequestHandlerFiltered; }), [(@"C:\dev\git\uController\samples\Program.cs", 68)] = ( (del, builder) => { builder.Metadata.Add(new SourceKey(@"C:\dev\git\uController\samples\Program.cs", 68)); builder.Metadata.Add(ResponseTypeMetadata.Create("application/json", typeof(int[]))); }, (del, builder) => { var handler = (System.Func)del; EndpointFilterDelegate filteredInvocation = null; var routePattern = (builder as RouteEndpointBuilder)?.RoutePattern; System.Func arg_queriesRouteOrQueryResolver = routePattern?.GetParameter("queries") is null ? ResolveByQuery : ResolveByRoute; if (builder.FilterFactories.Count > 0) { filteredInvocation = BuildFilterDelegate(ic => { if (ic.HttpContext.Response.StatusCode == 400) { return System.Threading.Tasks.ValueTask.FromResult(Results.Empty); } return System.Threading.Tasks.ValueTask.FromResult(handler(ic.GetArgument(0))); }, builder, handler.Method); } System.Threading.Tasks.Task RequestHandler(Microsoft.AspNetCore.Http.HttpContext httpContext) { var wasParamCheckFailure = false; var arg_queries_Value = arg_queriesRouteOrQueryResolver(httpContext, "queries").ToArray(); int[] arg_queries = default; for (var i = 0; i < arg_queries.Length; i++) { arg_queries ??= new int[arg_queries_Value.Length]; if (arg_queries_Value[i] == null || !int.TryParse(arg_queries_Value[i], out arg_queries[i])) { arg_queries[i] = default; wasParamCheckFailure = true; } } arg_queries ??= System.Array.Empty(); if (wasParamCheckFailure) { httpContext.Response.StatusCode = 400; return Task.CompletedTask; } var result = handler(arg_queries); return httpContext.Response.WriteAsJsonAsync(result); } async System.Threading.Tasks.Task RequestHandlerFiltered(Microsoft.AspNetCore.Http.HttpContext httpContext) { var wasParamCheckFailure = false; var arg_queries_Value = arg_queriesRouteOrQueryResolver(httpContext, "queries").ToArray(); int[] arg_queries = default; for (var i = 0; i < arg_queries.Length; i++) { arg_queries ??= new int[arg_queries_Value.Length]; if (arg_queries_Value[i] == null || !int.TryParse(arg_queries_Value[i], out arg_queries[i])) { arg_queries[i] = default; wasParamCheckFailure = true; } } arg_queries ??= System.Array.Empty(); if (wasParamCheckFailure) { httpContext.Response.StatusCode = 400; } var result = await filteredInvocation(new DefaultEndpointFilterInvocationContext(httpContext, arg_queries)); await ExecuteObjectResult(result, httpContext); } return filteredInvocation is null ? RequestHandler : RequestHandlerFiltered; }), [(@"C:\dev\git\uController\samples\Program.cs", 73)] = ( (del, builder) => { builder.Metadata.Add(new SourceKey(@"C:\dev\git\uController\samples\Program.cs", 73)); builder.Metadata.Add(ResponseTypeMetadata.Create("application/json", typeof(Person))); }, (del, builder) => { var handler = (System.Func)del; EndpointFilterDelegate filteredInvocation = null; if (builder.FilterFactories.Count > 0) { filteredInvocation = BuildFilterDelegate(ic => { if (ic.HttpContext.Response.StatusCode == 400) { return System.Threading.Tasks.ValueTask.FromResult(Results.Empty); } return System.Threading.Tasks.ValueTask.FromResult(handler()); }, builder, handler.Method); } System.Threading.Tasks.Task RequestHandler(Microsoft.AspNetCore.Http.HttpContext httpContext) { var result = handler(); return httpContext.Response.WriteAsJsonAsync(result); } async System.Threading.Tasks.Task RequestHandlerFiltered(Microsoft.AspNetCore.Http.HttpContext httpContext) { var result = await filteredInvocation(new DefaultEndpointFilterInvocationContext(httpContext)); await ExecuteObjectResult(result, httpContext); } return filteredInvocation is null ? RequestHandler : RequestHandlerFiltered; }), [(@"C:\dev\git\uController\samples\Program.cs", 79)] = ( (del, builder) => { builder.Metadata.Add(new SourceKey(@"C:\dev\git\uController\samples\Program.cs", 79)); builder.Metadata.Add(ResponseTypeMetadata.Create("text/plain")); }, (del, builder) => { var handler = (System.Func)del; EndpointFilterDelegate filteredInvocation = null; var routePattern = (builder as RouteEndpointBuilder)?.RoutePattern; System.Func arg_idRouteOrQueryResolver = routePattern?.GetParameter("id") is null ? ResolveByQuery : ResolveByRoute; if (builder.FilterFactories.Count > 0) { filteredInvocation = BuildFilterDelegate(ic => { if (ic.HttpContext.Response.StatusCode == 400) { return System.Threading.Tasks.ValueTask.FromResult(Results.Empty); } return System.Threading.Tasks.ValueTask.FromResult(handler(ic.GetArgument(0))); }, builder, handler.Method); } System.Threading.Tasks.Task RequestHandler(Microsoft.AspNetCore.Http.HttpContext httpContext) { var wasParamCheckFailure = false; var arg_id_Value = arg_idRouteOrQueryResolver(httpContext, "id").ToString(); int arg_id; if (arg_id_Value == null || !int.TryParse(arg_id_Value, out arg_id)) { arg_id = default; wasParamCheckFailure = true; } if (wasParamCheckFailure) { httpContext.Response.StatusCode = 400; return Task.CompletedTask; } var result = handler(arg_id); return httpContext.Response.WriteAsync(result); } async System.Threading.Tasks.Task RequestHandlerFiltered(Microsoft.AspNetCore.Http.HttpContext httpContext) { var wasParamCheckFailure = false; var arg_id_Value = arg_idRouteOrQueryResolver(httpContext, "id").ToString(); int arg_id; if (arg_id_Value == null || !int.TryParse(arg_id_Value, out arg_id)) { arg_id = default; wasParamCheckFailure = true; } if (wasParamCheckFailure) { httpContext.Response.StatusCode = 400; } var result = await filteredInvocation(new DefaultEndpointFilterInvocationContext(httpContext, arg_id)); await ExecuteObjectResult(result, httpContext); } return filteredInvocation is null ? RequestHandler : RequestHandlerFiltered; }), [(@"C:\dev\git\uController\samples\Program.cs", 81)] = ( (del, builder) => { builder.Metadata.Add(new SourceKey(@"C:\dev\git\uController\samples\Program.cs", 81)); builder.Metadata.Add(ResponseTypeMetadata.Create("text/plain")); }, (del, builder) => { var handler = (System.Func)del; EndpointFilterDelegate filteredInvocation = null; var routePattern = (builder as RouteEndpointBuilder)?.RoutePattern; System.Func arg_nameRouteOrQueryResolver = routePattern?.GetParameter("name") is null ? ResolveByQuery : ResolveByRoute; if (builder.FilterFactories.Count > 0) { filteredInvocation = BuildFilterDelegate(ic => { if (ic.HttpContext.Response.StatusCode == 400) { return System.Threading.Tasks.ValueTask.FromResult(Results.Empty); } return System.Threading.Tasks.ValueTask.FromResult(handler(ic.GetArgument(0))); }, builder, handler.Method); } System.Threading.Tasks.Task RequestHandler(Microsoft.AspNetCore.Http.HttpContext httpContext) { var arg_name = arg_nameRouteOrQueryResolver(httpContext, "name").ToString(); var result = handler(arg_name); return httpContext.Response.WriteAsync(result); } async System.Threading.Tasks.Task RequestHandlerFiltered(Microsoft.AspNetCore.Http.HttpContext httpContext) { var arg_name = arg_nameRouteOrQueryResolver(httpContext, "name").ToString(); var result = await filteredInvocation(new DefaultEndpointFilterInvocationContext(httpContext, arg_name)); await ExecuteObjectResult(result, httpContext); } return filteredInvocation is null ? RequestHandler : RequestHandlerFiltered; }), [(@"C:\dev\git\uController\samples\Program.cs", 82)] = ( (del, builder) => { builder.Metadata.Add(new SourceKey(@"C:\dev\git\uController\samples\Program.cs", 82)); builder.Metadata.Add(ResponseTypeMetadata.Create("text/plain")); }, (del, builder) => { var handler = (System.Func)del; EndpointFilterDelegate filteredInvocation = null; var routePattern = (builder as RouteEndpointBuilder)?.RoutePattern; System.Func arg_nameRouteOrQueryResolver = routePattern?.GetParameter("name") is null ? ResolveByQuery : ResolveByRoute; if (builder.FilterFactories.Count > 0) { filteredInvocation = BuildFilterDelegate(ic => { if (ic.HttpContext.Response.StatusCode == 400) { return System.Threading.Tasks.ValueTask.FromResult(Results.Empty); } return System.Threading.Tasks.ValueTask.FromResult(handler(ic.GetArgument(0))); }, builder, handler.Method); } System.Threading.Tasks.Task RequestHandler(Microsoft.AspNetCore.Http.HttpContext httpContext) { var arg_name = arg_nameRouteOrQueryResolver(httpContext, "name").ToString(); var result = handler(arg_name); return httpContext.Response.WriteAsync(result); } async System.Threading.Tasks.Task RequestHandlerFiltered(Microsoft.AspNetCore.Http.HttpContext httpContext) { var arg_name = arg_nameRouteOrQueryResolver(httpContext, "name").ToString(); var result = await filteredInvocation(new DefaultEndpointFilterInvocationContext(httpContext, arg_name)); await ExecuteObjectResult(result, httpContext); } return filteredInvocation is null ? RequestHandler : RequestHandlerFiltered; }), [(@"C:\dev\git\uController\samples\Program.cs", 84)] = ( (del, builder) => { builder.Metadata.Add(new SourceKey(@"C:\dev\git\uController\samples\Program.cs", 84)); builder.Metadata.Add(ResponseTypeMetadata.Create("text/plain")); }, (del, builder) => { var handler = (System.Func)del; EndpointFilterDelegate filteredInvocation = null; if (builder.FilterFactories.Count > 0) { filteredInvocation = BuildFilterDelegate(ic => { if (ic.HttpContext.Response.StatusCode == 400) { return System.Threading.Tasks.ValueTask.FromResult(Results.Empty); } return System.Threading.Tasks.ValueTask.FromResult(handler(ic.GetArgument(0))); }, builder, handler.Method); } System.Threading.Tasks.Task RequestHandler(Microsoft.AspNetCore.Http.HttpContext httpContext) { var wasParamCheckFailure = false; var arg_c_Value = httpContext.Request.RouteValues["c"]?.ToString(); Choices arg_c; if (arg_c_Value == null || !System.Enum.TryParse(arg_c_Value, true, out arg_c)) { arg_c = default; wasParamCheckFailure = true; } if (wasParamCheckFailure) { httpContext.Response.StatusCode = 400; return Task.CompletedTask; } var result = handler(arg_c); return httpContext.Response.WriteAsync(result); } async System.Threading.Tasks.Task RequestHandlerFiltered(Microsoft.AspNetCore.Http.HttpContext httpContext) { var wasParamCheckFailure = false; var arg_c_Value = httpContext.Request.RouteValues["c"]?.ToString(); Choices arg_c; if (arg_c_Value == null || !System.Enum.TryParse(arg_c_Value, true, out arg_c)) { arg_c = default; wasParamCheckFailure = true; } if (wasParamCheckFailure) { httpContext.Response.StatusCode = 400; } var result = await filteredInvocation(new DefaultEndpointFilterInvocationContext(httpContext, arg_c)); await ExecuteObjectResult(result, httpContext); } return filteredInvocation is null ? RequestHandler : RequestHandlerFiltered; }), [(@"C:\dev\git\uController\samples\Program.cs", 103)] = ( (del, builder) => { builder.Metadata.Add(new SourceKey(@"C:\dev\git\uController\samples\Program.cs", 103)); builder.Metadata.Add(ResponseTypeMetadata.Create("application/json", typeof(int))); }, (del, builder) => { var handler = (System.Func)del; EndpointFilterDelegate filteredInvocation = null; var routePattern = (builder as RouteEndpointBuilder)?.RoutePattern; System.Func arg_xRouteOrQueryResolver = routePattern?.GetParameter("x") is null ? ResolveByQuery : ResolveByRoute; if (builder.FilterFactories.Count > 0) { filteredInvocation = BuildFilterDelegate(ic => { if (ic.HttpContext.Response.StatusCode == 400) { return System.Threading.Tasks.ValueTask.FromResult(Results.Empty); } return System.Threading.Tasks.ValueTask.FromResult(handler(ic.GetArgument(0))); }, builder, handler.Method); } System.Threading.Tasks.Task RequestHandler(Microsoft.AspNetCore.Http.HttpContext httpContext) { var wasParamCheckFailure = false; var arg_x_Value = arg_xRouteOrQueryResolver(httpContext, "x").ToString(); int arg_x; if (arg_x_Value == null || !int.TryParse(arg_x_Value, out arg_x)) { arg_x = default; wasParamCheckFailure = true; } if (wasParamCheckFailure) { httpContext.Response.StatusCode = 400; return Task.CompletedTask; } var result = handler(arg_x); return httpContext.Response.WriteAsJsonAsync(result); } async System.Threading.Tasks.Task RequestHandlerFiltered(Microsoft.AspNetCore.Http.HttpContext httpContext) { var wasParamCheckFailure = false; var arg_x_Value = arg_xRouteOrQueryResolver(httpContext, "x").ToString(); int arg_x; if (arg_x_Value == null || !int.TryParse(arg_x_Value, out arg_x)) { arg_x = default; wasParamCheckFailure = true; } if (wasParamCheckFailure) { httpContext.Response.StatusCode = 400; } var result = await filteredInvocation(new DefaultEndpointFilterInvocationContext(httpContext, arg_x)); await ExecuteObjectResult(result, httpContext); } return filteredInvocation is null ? RequestHandler : RequestHandlerFiltered; }), [(@"C:\dev\git\uController\samples\Program.cs", 104)] = ( (del, builder) => { builder.Metadata.Add(new SourceKey(@"C:\dev\git\uController\samples\Program.cs", 104)); }, (del, builder) => { var handler = (System.Action)del; EndpointFilterDelegate filteredInvocation = null; var routePattern = (builder as RouteEndpointBuilder)?.RoutePattern; System.Func arg_xRouteOrQueryResolver = routePattern?.GetParameter("x") is null ? ResolveByQuery : ResolveByRoute; System.Func arg_yRouteOrQueryResolver = routePattern?.GetParameter("y") is null ? ResolveByQuery : ResolveByRoute; if (builder.FilterFactories.Count > 0) { filteredInvocation = BuildFilterDelegate(ic => { if (ic.HttpContext.Response.StatusCode == 400) { return System.Threading.Tasks.ValueTask.FromResult(Results.Empty); } handler(ic.GetArgument(0), ic.GetArgument(1)); return System.Threading.Tasks.ValueTask.FromResult(Results.Empty); }, builder, handler.Method); } System.Threading.Tasks.Task RequestHandler(Microsoft.AspNetCore.Http.HttpContext httpContext) { var wasParamCheckFailure = false; var arg_x_Value = arg_xRouteOrQueryResolver(httpContext, "x").ToString(); int arg_x; if (arg_x_Value == null || !int.TryParse(arg_x_Value, out arg_x)) { arg_x = default; wasParamCheckFailure = true; } var arg_y_Value = arg_yRouteOrQueryResolver(httpContext, "y").ToString(); int arg_y; if (arg_y_Value == null || !int.TryParse(arg_y_Value, out arg_y)) { arg_y = default; wasParamCheckFailure = true; } if (wasParamCheckFailure) { httpContext.Response.StatusCode = 400; return Task.CompletedTask; } handler(arg_x, arg_y); return System.Threading.Tasks.Task.CompletedTask; } async System.Threading.Tasks.Task RequestHandlerFiltered(Microsoft.AspNetCore.Http.HttpContext httpContext) { var wasParamCheckFailure = false; var arg_x_Value = arg_xRouteOrQueryResolver(httpContext, "x").ToString(); int arg_x; if (arg_x_Value == null || !int.TryParse(arg_x_Value, out arg_x)) { arg_x = default; wasParamCheckFailure = true; } var arg_y_Value = arg_yRouteOrQueryResolver(httpContext, "y").ToString(); int arg_y; if (arg_y_Value == null || !int.TryParse(arg_y_Value, out arg_y)) { arg_y = default; wasParamCheckFailure = true; } if (wasParamCheckFailure) { httpContext.Response.StatusCode = 400; } var result = await filteredInvocation(new DefaultEndpointFilterInvocationContext(httpContext, arg_x, arg_y)); await ExecuteObjectResult(result, httpContext); } return filteredInvocation is null ? RequestHandler : RequestHandlerFiltered; }), [(@"C:\dev\git\uController\samples\Program.cs", 105)] = ( (del, builder) => { builder.Metadata.Add(new SourceKey(@"C:\dev\git\uController\samples\Program.cs", 105)); builder.Metadata.Add(ResponseTypeMetadata.Create("application/json", typeof(int))); }, (del, builder) => { var handler = (System.Func)del; EndpointFilterDelegate filteredInvocation = null; var routePattern = (builder as RouteEndpointBuilder)?.RoutePattern; System.Func arg_xRouteOrQueryResolver = routePattern?.GetParameter("x") is null ? ResolveByQuery : ResolveByRoute; if (builder.FilterFactories.Count > 0) { filteredInvocation = BuildFilterDelegate(ic => { if (ic.HttpContext.Response.StatusCode == 400) { return System.Threading.Tasks.ValueTask.FromResult(Results.Empty); } return System.Threading.Tasks.ValueTask.FromResult(handler(ic.GetArgument(0))); }, builder, handler.Method); } System.Threading.Tasks.Task RequestHandler(Microsoft.AspNetCore.Http.HttpContext httpContext) { var wasParamCheckFailure = false; var arg_x_Value = arg_xRouteOrQueryResolver(httpContext, "x").ToString(); int arg_x; if (arg_x_Value == null || !int.TryParse(arg_x_Value, out arg_x)) { arg_x = default; wasParamCheckFailure = true; } if (wasParamCheckFailure) { httpContext.Response.StatusCode = 400; return Task.CompletedTask; } var result = handler(arg_x); return httpContext.Response.WriteAsJsonAsync(result); } async System.Threading.Tasks.Task RequestHandlerFiltered(Microsoft.AspNetCore.Http.HttpContext httpContext) { var wasParamCheckFailure = false; var arg_x_Value = arg_xRouteOrQueryResolver(httpContext, "x").ToString(); int arg_x; if (arg_x_Value == null || !int.TryParse(arg_x_Value, out arg_x)) { arg_x = default; wasParamCheckFailure = true; } if (wasParamCheckFailure) { httpContext.Response.StatusCode = 400; } var result = await filteredInvocation(new DefaultEndpointFilterInvocationContext(httpContext, arg_x)); await ExecuteObjectResult(result, httpContext); } return filteredInvocation is null ? RequestHandler : RequestHandlerFiltered; }), [(@"C:\dev\git\uController\samples\Program.cs", 106)] = ( (del, builder) => { builder.Metadata.Add(new SourceKey(@"C:\dev\git\uController\samples\Program.cs", 106)); }, (del, builder) => { var handler = (System.Action)del; EndpointFilterDelegate filteredInvocation = null; var routePattern = (builder as RouteEndpointBuilder)?.RoutePattern; System.Func arg_xRouteOrQueryResolver = routePattern?.GetParameter("x") is null ? ResolveByQuery : ResolveByRoute; System.Func arg_yRouteOrQueryResolver = routePattern?.GetParameter("y") is null ? ResolveByQuery : ResolveByRoute; if (builder.FilterFactories.Count > 0) { filteredInvocation = BuildFilterDelegate(ic => { if (ic.HttpContext.Response.StatusCode == 400) { return System.Threading.Tasks.ValueTask.FromResult(Results.Empty); } handler(ic.GetArgument(0), ic.GetArgument(1)); return System.Threading.Tasks.ValueTask.FromResult(Results.Empty); }, builder, handler.Method); } System.Threading.Tasks.Task RequestHandler(Microsoft.AspNetCore.Http.HttpContext httpContext) { var wasParamCheckFailure = false; var arg_x_Value = arg_xRouteOrQueryResolver(httpContext, "x").ToString(); int arg_x; if (arg_x_Value == null || !int.TryParse(arg_x_Value, out arg_x)) { arg_x = default; wasParamCheckFailure = true; } var arg_y_Value = arg_yRouteOrQueryResolver(httpContext, "y").ToString(); int arg_y; if (arg_y_Value == null || !int.TryParse(arg_y_Value, out arg_y)) { arg_y = default; wasParamCheckFailure = true; } if (wasParamCheckFailure) { httpContext.Response.StatusCode = 400; return Task.CompletedTask; } handler(arg_x, arg_y); return System.Threading.Tasks.Task.CompletedTask; } async System.Threading.Tasks.Task RequestHandlerFiltered(Microsoft.AspNetCore.Http.HttpContext httpContext) { var wasParamCheckFailure = false; var arg_x_Value = arg_xRouteOrQueryResolver(httpContext, "x").ToString(); int arg_x; if (arg_x_Value == null || !int.TryParse(arg_x_Value, out arg_x)) { arg_x = default; wasParamCheckFailure = true; } var arg_y_Value = arg_yRouteOrQueryResolver(httpContext, "y").ToString(); int arg_y; if (arg_y_Value == null || !int.TryParse(arg_y_Value, out arg_y)) { arg_y = default; wasParamCheckFailure = true; } if (wasParamCheckFailure) { httpContext.Response.StatusCode = 400; } var result = await filteredInvocation(new DefaultEndpointFilterInvocationContext(httpContext, arg_x, arg_y)); await ExecuteObjectResult(result, httpContext); } return filteredInvocation is null ? RequestHandler : RequestHandlerFiltered; }), [(@"C:\dev\git\uController\samples\Program.cs", 107)] = ( (del, builder) => { builder.Metadata.Add(new SourceKey(@"C:\dev\git\uController\samples\Program.cs", 107)); builder.Metadata.Add(ResponseTypeMetadata.Create("application/json", typeof(int))); }, (del, builder) => { var handler = (System.Func)del; EndpointFilterDelegate filteredInvocation = null; var routePattern = (builder as RouteEndpointBuilder)?.RoutePattern; System.Func arg_xRouteOrQueryResolver = routePattern?.GetParameter("x") is null ? ResolveByQuery : ResolveByRoute; if (builder.FilterFactories.Count > 0) { filteredInvocation = BuildFilterDelegate(ic => { if (ic.HttpContext.Response.StatusCode == 400) { return System.Threading.Tasks.ValueTask.FromResult(Results.Empty); } return System.Threading.Tasks.ValueTask.FromResult(handler(ic.GetArgument(0))); }, builder, handler.Method); } System.Threading.Tasks.Task RequestHandler(Microsoft.AspNetCore.Http.HttpContext httpContext) { var wasParamCheckFailure = false; var arg_x_Value = arg_xRouteOrQueryResolver(httpContext, "x").ToString(); int arg_x; if (arg_x_Value == null || !int.TryParse(arg_x_Value, out arg_x)) { arg_x = default; wasParamCheckFailure = true; } if (wasParamCheckFailure) { httpContext.Response.StatusCode = 400; return Task.CompletedTask; } var result = handler(arg_x); return httpContext.Response.WriteAsJsonAsync(result); } async System.Threading.Tasks.Task RequestHandlerFiltered(Microsoft.AspNetCore.Http.HttpContext httpContext) { var wasParamCheckFailure = false; var arg_x_Value = arg_xRouteOrQueryResolver(httpContext, "x").ToString(); int arg_x; if (arg_x_Value == null || !int.TryParse(arg_x_Value, out arg_x)) { arg_x = default; wasParamCheckFailure = true; } if (wasParamCheckFailure) { httpContext.Response.StatusCode = 400; } var result = await filteredInvocation(new DefaultEndpointFilterInvocationContext(httpContext, arg_x)); await ExecuteObjectResult(result, httpContext); } return filteredInvocation is null ? RequestHandler : RequestHandlerFiltered; }), [(@"C:\dev\git\uController\samples\Program.cs", 108)] = ( (del, builder) => { builder.Metadata.Add(new SourceKey(@"C:\dev\git\uController\samples\Program.cs", 108)); }, (del, builder) => { var handler = (System.Action)del; EndpointFilterDelegate filteredInvocation = null; var routePattern = (builder as RouteEndpointBuilder)?.RoutePattern; System.Func arg_xRouteOrQueryResolver = routePattern?.GetParameter("x") is null ? ResolveByQuery : ResolveByRoute; System.Func arg_yRouteOrQueryResolver = routePattern?.GetParameter("y") is null ? ResolveByQuery : ResolveByRoute; if (builder.FilterFactories.Count > 0) { filteredInvocation = BuildFilterDelegate(ic => { if (ic.HttpContext.Response.StatusCode == 400) { return System.Threading.Tasks.ValueTask.FromResult(Results.Empty); } handler(ic.GetArgument(0), ic.GetArgument(1)); return System.Threading.Tasks.ValueTask.FromResult(Results.Empty); }, builder, handler.Method); } System.Threading.Tasks.Task RequestHandler(Microsoft.AspNetCore.Http.HttpContext httpContext) { var wasParamCheckFailure = false; var arg_x_Value = arg_xRouteOrQueryResolver(httpContext, "x").ToString(); int arg_x; if (arg_x_Value == null || !int.TryParse(arg_x_Value, out arg_x)) { arg_x = default; wasParamCheckFailure = true; } var arg_y_Value = arg_yRouteOrQueryResolver(httpContext, "y").ToString(); int arg_y; if (arg_y_Value == null || !int.TryParse(arg_y_Value, out arg_y)) { arg_y = default; wasParamCheckFailure = true; } if (wasParamCheckFailure) { httpContext.Response.StatusCode = 400; return Task.CompletedTask; } handler(arg_x, arg_y); return System.Threading.Tasks.Task.CompletedTask; } async System.Threading.Tasks.Task RequestHandlerFiltered(Microsoft.AspNetCore.Http.HttpContext httpContext) { var wasParamCheckFailure = false; var arg_x_Value = arg_xRouteOrQueryResolver(httpContext, "x").ToString(); int arg_x; if (arg_x_Value == null || !int.TryParse(arg_x_Value, out arg_x)) { arg_x = default; wasParamCheckFailure = true; } var arg_y_Value = arg_yRouteOrQueryResolver(httpContext, "y").ToString(); int arg_y; if (arg_y_Value == null || !int.TryParse(arg_y_Value, out arg_y)) { arg_y = default; wasParamCheckFailure = true; } if (wasParamCheckFailure) { httpContext.Response.StatusCode = 400; } var result = await filteredInvocation(new DefaultEndpointFilterInvocationContext(httpContext, arg_x, arg_y)); await ExecuteObjectResult(result, httpContext); } return filteredInvocation is null ? RequestHandler : RequestHandlerFiltered; }), [(@"C:\dev\git\uController\samples\Program.cs", 109)] = ( (del, builder) => { builder.Metadata.Add(new SourceKey(@"C:\dev\git\uController\samples\Program.cs", 109)); builder.Metadata.Add(ResponseTypeMetadata.Create("application/json", typeof(int))); }, (del, builder) => { var handler = (System.Func)del; EndpointFilterDelegate filteredInvocation = null; var routePattern = (builder as RouteEndpointBuilder)?.RoutePattern; System.Func arg_xRouteOrQueryResolver = routePattern?.GetParameter("x") is null ? ResolveByQuery : ResolveByRoute; if (builder.FilterFactories.Count > 0) { filteredInvocation = BuildFilterDelegate(ic => { if (ic.HttpContext.Response.StatusCode == 400) { return System.Threading.Tasks.ValueTask.FromResult(Results.Empty); } return System.Threading.Tasks.ValueTask.FromResult(handler(ic.GetArgument(0))); }, builder, handler.Method); } System.Threading.Tasks.Task RequestHandler(Microsoft.AspNetCore.Http.HttpContext httpContext) { var wasParamCheckFailure = false; var arg_x_Value = arg_xRouteOrQueryResolver(httpContext, "x").ToString(); int arg_x; if (arg_x_Value == null || !int.TryParse(arg_x_Value, out arg_x)) { arg_x = default; wasParamCheckFailure = true; } if (wasParamCheckFailure) { httpContext.Response.StatusCode = 400; return Task.CompletedTask; } var result = handler(arg_x); return httpContext.Response.WriteAsJsonAsync(result); } async System.Threading.Tasks.Task RequestHandlerFiltered(Microsoft.AspNetCore.Http.HttpContext httpContext) { var wasParamCheckFailure = false; var arg_x_Value = arg_xRouteOrQueryResolver(httpContext, "x").ToString(); int arg_x; if (arg_x_Value == null || !int.TryParse(arg_x_Value, out arg_x)) { arg_x = default; wasParamCheckFailure = true; } if (wasParamCheckFailure) { httpContext.Response.StatusCode = 400; } var result = await filteredInvocation(new DefaultEndpointFilterInvocationContext(httpContext, arg_x)); await ExecuteObjectResult(result, httpContext); } return filteredInvocation is null ? RequestHandler : RequestHandlerFiltered; }), [(@"C:\dev\git\uController\samples\Program.cs", 110)] = ( (del, builder) => { builder.Metadata.Add(new SourceKey(@"C:\dev\git\uController\samples\Program.cs", 110)); }, (del, builder) => { var handler = (System.Action)del; EndpointFilterDelegate filteredInvocation = null; var routePattern = (builder as RouteEndpointBuilder)?.RoutePattern; System.Func arg_xRouteOrQueryResolver = routePattern?.GetParameter("x") is null ? ResolveByQuery : ResolveByRoute; System.Func arg_yRouteOrQueryResolver = routePattern?.GetParameter("y") is null ? ResolveByQuery : ResolveByRoute; if (builder.FilterFactories.Count > 0) { filteredInvocation = BuildFilterDelegate(ic => { if (ic.HttpContext.Response.StatusCode == 400) { return System.Threading.Tasks.ValueTask.FromResult(Results.Empty); } handler(ic.GetArgument(0), ic.GetArgument(1)); return System.Threading.Tasks.ValueTask.FromResult(Results.Empty); }, builder, handler.Method); } System.Threading.Tasks.Task RequestHandler(Microsoft.AspNetCore.Http.HttpContext httpContext) { var wasParamCheckFailure = false; var arg_x_Value = arg_xRouteOrQueryResolver(httpContext, "x").ToString(); int arg_x; if (arg_x_Value == null || !int.TryParse(arg_x_Value, out arg_x)) { arg_x = default; wasParamCheckFailure = true; } var arg_y_Value = arg_yRouteOrQueryResolver(httpContext, "y").ToString(); int arg_y; if (arg_y_Value == null || !int.TryParse(arg_y_Value, out arg_y)) { arg_y = default; wasParamCheckFailure = true; } if (wasParamCheckFailure) { httpContext.Response.StatusCode = 400; return Task.CompletedTask; } handler(arg_x, arg_y); return System.Threading.Tasks.Task.CompletedTask; } async System.Threading.Tasks.Task RequestHandlerFiltered(Microsoft.AspNetCore.Http.HttpContext httpContext) { var wasParamCheckFailure = false; var arg_x_Value = arg_xRouteOrQueryResolver(httpContext, "x").ToString(); int arg_x; if (arg_x_Value == null || !int.TryParse(arg_x_Value, out arg_x)) { arg_x = default; wasParamCheckFailure = true; } var arg_y_Value = arg_yRouteOrQueryResolver(httpContext, "y").ToString(); int arg_y; if (arg_y_Value == null || !int.TryParse(arg_y_Value, out arg_y)) { arg_y = default; wasParamCheckFailure = true; } if (wasParamCheckFailure) { httpContext.Response.StatusCode = 400; } var result = await filteredInvocation(new DefaultEndpointFilterInvocationContext(httpContext, arg_x, arg_y)); await ExecuteObjectResult(result, httpContext); } return filteredInvocation is null ? RequestHandler : RequestHandlerFiltered; }), [(@"C:\dev\git\uController\samples\Program.cs", 111)] = ( (del, builder) => { builder.Metadata.Add(new SourceKey(@"C:\dev\git\uController\samples\Program.cs", 111)); builder.Metadata.Add(ResponseTypeMetadata.Create("application/json", typeof(int))); }, (del, builder) => { var handler = (System.Func)del; EndpointFilterDelegate filteredInvocation = null; var routePattern = (builder as RouteEndpointBuilder)?.RoutePattern; System.Func arg_xRouteOrQueryResolver = routePattern?.GetParameter("x") is null ? ResolveByQuery : ResolveByRoute; if (builder.FilterFactories.Count > 0) { filteredInvocation = BuildFilterDelegate(ic => { if (ic.HttpContext.Response.StatusCode == 400) { return System.Threading.Tasks.ValueTask.FromResult(Results.Empty); } return System.Threading.Tasks.ValueTask.FromResult(handler(ic.GetArgument(0))); }, builder, handler.Method); } System.Threading.Tasks.Task RequestHandler(Microsoft.AspNetCore.Http.HttpContext httpContext) { var wasParamCheckFailure = false; var arg_x_Value = arg_xRouteOrQueryResolver(httpContext, "x").ToString(); int arg_x; if (arg_x_Value == null || !int.TryParse(arg_x_Value, out arg_x)) { arg_x = default; wasParamCheckFailure = true; } if (wasParamCheckFailure) { httpContext.Response.StatusCode = 400; return Task.CompletedTask; } var result = handler(arg_x); return httpContext.Response.WriteAsJsonAsync(result); } async System.Threading.Tasks.Task RequestHandlerFiltered(Microsoft.AspNetCore.Http.HttpContext httpContext) { var wasParamCheckFailure = false; var arg_x_Value = arg_xRouteOrQueryResolver(httpContext, "x").ToString(); int arg_x; if (arg_x_Value == null || !int.TryParse(arg_x_Value, out arg_x)) { arg_x = default; wasParamCheckFailure = true; } if (wasParamCheckFailure) { httpContext.Response.StatusCode = 400; } var result = await filteredInvocation(new DefaultEndpointFilterInvocationContext(httpContext, arg_x)); await ExecuteObjectResult(result, httpContext); } return filteredInvocation is null ? RequestHandler : RequestHandlerFiltered; }), [(@"C:\dev\git\uController\samples\Program.cs", 112)] = ( (del, builder) => { builder.Metadata.Add(new SourceKey(@"C:\dev\git\uController\samples\Program.cs", 112)); }, (del, builder) => { var handler = (System.Action)del; EndpointFilterDelegate filteredInvocation = null; var routePattern = (builder as RouteEndpointBuilder)?.RoutePattern; System.Func arg_xRouteOrQueryResolver = routePattern?.GetParameter("x") is null ? ResolveByQuery : ResolveByRoute; System.Func arg_yRouteOrQueryResolver = routePattern?.GetParameter("y") is null ? ResolveByQuery : ResolveByRoute; if (builder.FilterFactories.Count > 0) { filteredInvocation = BuildFilterDelegate(ic => { if (ic.HttpContext.Response.StatusCode == 400) { return System.Threading.Tasks.ValueTask.FromResult(Results.Empty); } handler(ic.GetArgument(0), ic.GetArgument(1)); return System.Threading.Tasks.ValueTask.FromResult(Results.Empty); }, builder, handler.Method); } System.Threading.Tasks.Task RequestHandler(Microsoft.AspNetCore.Http.HttpContext httpContext) { var wasParamCheckFailure = false; var arg_x_Value = arg_xRouteOrQueryResolver(httpContext, "x").ToString(); int arg_x; if (arg_x_Value == null || !int.TryParse(arg_x_Value, out arg_x)) { arg_x = default; wasParamCheckFailure = true; } var arg_y_Value = arg_yRouteOrQueryResolver(httpContext, "y").ToString(); int arg_y; if (arg_y_Value == null || !int.TryParse(arg_y_Value, out arg_y)) { arg_y = default; wasParamCheckFailure = true; } if (wasParamCheckFailure) { httpContext.Response.StatusCode = 400; return Task.CompletedTask; } handler(arg_x, arg_y); return System.Threading.Tasks.Task.CompletedTask; } async System.Threading.Tasks.Task RequestHandlerFiltered(Microsoft.AspNetCore.Http.HttpContext httpContext) { var wasParamCheckFailure = false; var arg_x_Value = arg_xRouteOrQueryResolver(httpContext, "x").ToString(); int arg_x; if (arg_x_Value == null || !int.TryParse(arg_x_Value, out arg_x)) { arg_x = default; wasParamCheckFailure = true; } var arg_y_Value = arg_yRouteOrQueryResolver(httpContext, "y").ToString(); int arg_y; if (arg_y_Value == null || !int.TryParse(arg_y_Value, out arg_y)) { arg_y = default; wasParamCheckFailure = true; } if (wasParamCheckFailure) { httpContext.Response.StatusCode = 400; } var result = await filteredInvocation(new DefaultEndpointFilterInvocationContext(httpContext, arg_x, arg_y)); await ExecuteObjectResult(result, httpContext); } return filteredInvocation is null ? RequestHandler : RequestHandlerFiltered; }), [(@"C:\dev\git\uController\samples\Program.cs", 113)] = ( (del, builder) => { builder.Metadata.Add(new SourceKey(@"C:\dev\git\uController\samples\Program.cs", 113)); builder.Metadata.Add(ResponseTypeMetadata.Create("application/json", typeof(int))); }, (del, builder) => { var handler = (System.Func)del; EndpointFilterDelegate filteredInvocation = null; if (builder.FilterFactories.Count > 0) { filteredInvocation = BuildFilterDelegate(ic => { if (ic.HttpContext.Response.StatusCode == 400) { return System.Threading.Tasks.ValueTask.FromResult(Results.Empty); } return System.Threading.Tasks.ValueTask.FromResult(handler(ic.GetArgument(0))); }, builder, handler.Method); } System.Threading.Tasks.Task RequestHandler(Microsoft.AspNetCore.Http.HttpContext httpContext) { var wasParamCheckFailure = false; var arg_n_Value = httpContext.Request.RouteValues["n"]?.ToString(); int arg_n; if (arg_n_Value == null || !int.TryParse(arg_n_Value, out arg_n)) { arg_n = default; wasParamCheckFailure = true; } if (wasParamCheckFailure) { httpContext.Response.StatusCode = 400; return Task.CompletedTask; } var result = handler(arg_n); return httpContext.Response.WriteAsJsonAsync(result); } async System.Threading.Tasks.Task RequestHandlerFiltered(Microsoft.AspNetCore.Http.HttpContext httpContext) { var wasParamCheckFailure = false; var arg_n_Value = httpContext.Request.RouteValues["n"]?.ToString(); int arg_n; if (arg_n_Value == null || !int.TryParse(arg_n_Value, out arg_n)) { arg_n = default; wasParamCheckFailure = true; } if (wasParamCheckFailure) { httpContext.Response.StatusCode = 400; } var result = await filteredInvocation(new DefaultEndpointFilterInvocationContext(httpContext, arg_n)); await ExecuteObjectResult(result, httpContext); } return filteredInvocation is null ? RequestHandler : RequestHandlerFiltered; }), [(@"C:\dev\git\uController\samples\Program.cs", 124)] = ( (del, builder) => { builder.Metadata.Add(new SourceKey(@"C:\dev\git\uController\samples\Program.cs", 124)); builder.Metadata.Add(ResponseTypeMetadata.Create("text/plain")); }, (del, builder) => { var handler = (System.Func)del; EndpointFilterDelegate filteredInvocation = null; if (builder.FilterFactories.Count > 0) { filteredInvocation = BuildFilterDelegate(ic => { if (ic.HttpContext.Response.StatusCode == 400) { return System.Threading.Tasks.ValueTask.FromResult(Results.Empty); } return System.Threading.Tasks.ValueTask.FromResult(handler(ic.GetArgument(0))); }, builder, handler.Method); } System.Threading.Tasks.Task RequestHandler(Microsoft.AspNetCore.Http.HttpContext httpContext) { var arg_name = httpContext.Request.RouteValues["name"]?.ToString(); var result = handler(arg_name); return httpContext.Response.WriteAsync(result); } async System.Threading.Tasks.Task RequestHandlerFiltered(Microsoft.AspNetCore.Http.HttpContext httpContext) { var arg_name = httpContext.Request.RouteValues["name"]?.ToString(); var result = await filteredInvocation(new DefaultEndpointFilterInvocationContext(httpContext, arg_name)); await ExecuteObjectResult(result, httpContext); } return filteredInvocation is null ? RequestHandler : RequestHandlerFiltered; }), [(@"C:\dev\git\uController\samples\Program.cs", 126)] = ( (del, builder) => { builder.Metadata.Add(new SourceKey(@"C:\dev\git\uController\samples\Program.cs", 126)); builder.Metadata.Add(ResponseTypeMetadata.Create("application/json", typeof(Parsable))); }, (del, builder) => { var handler = (System.Func)del; EndpointFilterDelegate filteredInvocation = null; if (builder.FilterFactories.Count > 0) { filteredInvocation = BuildFilterDelegate(ic => { if (ic.HttpContext.Response.StatusCode == 400) { return System.Threading.Tasks.ValueTask.FromResult(Results.Empty); } return System.Threading.Tasks.ValueTask.FromResult(handler(ic.GetArgument(0))); }, builder, handler.Method); } System.Threading.Tasks.Task RequestHandler(Microsoft.AspNetCore.Http.HttpContext httpContext) { var wasParamCheckFailure = false; var arg_p_Value = httpContext.Request.Query["p"].ToString(); Parsable arg_p; if (arg_p_Value == null || !Parsable.TryParse(arg_p_Value, System.Globalization.CultureInfo.InvariantCulture, out arg_p)) { arg_p = default; wasParamCheckFailure = true; } if (wasParamCheckFailure) { httpContext.Response.StatusCode = 400; return Task.CompletedTask; } var result = handler(arg_p); return httpContext.Response.WriteAsJsonAsync(result); } async System.Threading.Tasks.Task RequestHandlerFiltered(Microsoft.AspNetCore.Http.HttpContext httpContext) { var wasParamCheckFailure = false; var arg_p_Value = httpContext.Request.Query["p"].ToString(); Parsable arg_p; if (arg_p_Value == null || !Parsable.TryParse(arg_p_Value, System.Globalization.CultureInfo.InvariantCulture, out arg_p)) { arg_p = default; wasParamCheckFailure = true; } if (wasParamCheckFailure) { httpContext.Response.StatusCode = 400; } var result = await filteredInvocation(new DefaultEndpointFilterInvocationContext(httpContext, arg_p)); await ExecuteObjectResult(result, httpContext); } return filteredInvocation is null ? RequestHandler : RequestHandlerFiltered; }), [(@"C:\dev\git\uController\samples\Program.cs", 128)] = ( (del, builder) => { builder.Metadata.Add(new SourceKey(@"C:\dev\git\uController\samples\Program.cs", 128)); builder.Metadata.Add(ResponseTypeMetadata.Create("text/plain")); }, (del, builder) => { var handler = (System.Func)del; EndpointFilterDelegate filteredInvocation = null; if (builder.FilterFactories.Count > 0) { filteredInvocation = BuildFilterDelegate(ic => { if (ic.HttpContext.Response.StatusCode == 400) { return System.Threading.Tasks.ValueTask.FromResult(Results.Empty); } return System.Threading.Tasks.ValueTask.FromResult(handler(ic.GetArgument(0))); }, builder, handler.Method); } System.Threading.Tasks.Task RequestHandler(Microsoft.AspNetCore.Http.HttpContext httpContext) { var arg_context = httpContext; var result = handler(arg_context); return httpContext.Response.WriteAsync(result); } async System.Threading.Tasks.Task RequestHandlerFiltered(Microsoft.AspNetCore.Http.HttpContext httpContext) { var arg_context = httpContext; var result = await filteredInvocation(new DefaultEndpointFilterInvocationContext(httpContext, arg_context)); await ExecuteObjectResult(result, httpContext); } return filteredInvocation is null ? RequestHandler : RequestHandlerFiltered; }), [(@"C:\dev\git\uController\samples\Wrapper.cs", 15)] = ( (del, builder) => { builder.Metadata.Add(new SourceKey(@"C:\dev\git\uController\samples\Wrapper.cs", 15)); builder.Metadata.Add(ResponseTypeMetadata.Create("text/plain")); }, (del, builder) => { var handler = (System.Func)del; EndpointFilterDelegate filteredInvocation = null; var routePattern = (builder as RouteEndpointBuilder)?.RoutePattern; System.Func arg_idRouteOrQueryResolver = routePattern?.GetParameter("id") is null ? ResolveByQuery : ResolveByRoute; if (builder.FilterFactories.Count > 0) { filteredInvocation = BuildFilterDelegate(ic => { if (ic.HttpContext.Response.StatusCode == 400) { return System.Threading.Tasks.ValueTask.FromResult(Results.Empty); } return System.Threading.Tasks.ValueTask.FromResult(handler(ic.GetArgument(0))); }, builder, handler.Method); } System.Threading.Tasks.Task RequestHandler(Microsoft.AspNetCore.Http.HttpContext httpContext) { var wasParamCheckFailure = false; var arg_id_Value = arg_idRouteOrQueryResolver(httpContext, "id").ToString(); int arg_id; if (arg_id_Value == null || !int.TryParse(arg_id_Value, out arg_id)) { arg_id = default; wasParamCheckFailure = true; } if (wasParamCheckFailure) { httpContext.Response.StatusCode = 400; return Task.CompletedTask; } var result = handler(arg_id); return httpContext.Response.WriteAsync(result); } async System.Threading.Tasks.Task RequestHandlerFiltered(Microsoft.AspNetCore.Http.HttpContext httpContext) { var wasParamCheckFailure = false; var arg_id_Value = arg_idRouteOrQueryResolver(httpContext, "id").ToString(); int arg_id; if (arg_id_Value == null || !int.TryParse(arg_id_Value, out arg_id)) { arg_id = default; wasParamCheckFailure = true; } if (wasParamCheckFailure) { httpContext.Response.StatusCode = 400; } var result = await filteredInvocation(new DefaultEndpointFilterInvocationContext(httpContext, arg_id)); await ExecuteObjectResult(result, httpContext); } return filteredInvocation is null ? RequestHandler : RequestHandlerFiltered; }), }; /// /// Adds a to the that matches HTTP GET requests /// for the specified pattern. /// /// The to add the route to. /// The route pattern. /// The delegate executed when the endpoint is matched. /// A that can be used to further customize the endpoint. internal static Microsoft.AspNetCore.Builder.RouteHandlerBuilder MapGet(this Microsoft.AspNetCore.Routing.IEndpointRouteBuilder endpoints, string pattern, System.Func>> handler, [System.Runtime.CompilerServices.CallerFilePath] string filePath = "", [System.Runtime.CompilerServices.CallerLineNumber]int lineNumber = 0) { return MapCore(endpoints, pattern, handler, GetVerb, filePath, lineNumber); } /// /// Adds a to the that matches HTTP GET requests /// for the specified pattern. /// /// The to add the route to. /// The route pattern. /// The delegate executed when the endpoint is matched. /// A that can be used to further customize the endpoint. internal static Microsoft.AspNetCore.Builder.RouteHandlerBuilder MapGet(this Microsoft.AspNetCore.Routing.IEndpointRouteBuilder endpoints, string pattern, System.Func> handler, [System.Runtime.CompilerServices.CallerFilePath] string filePath = "", [System.Runtime.CompilerServices.CallerLineNumber]int lineNumber = 0) { return MapCore(endpoints, pattern, handler, GetVerb, filePath, lineNumber); } /// /// Adds a to the that matches HTTP PUT requests /// for the specified pattern. /// /// The to add the route to. /// The route pattern. /// The delegate executed when the endpoint is matched. /// A that can be used to further customize the endpoint. internal static Microsoft.AspNetCore.Builder.RouteHandlerBuilder MapPut(this Microsoft.AspNetCore.Routing.IEndpointRouteBuilder endpoints, string pattern, System.Func> handler, [System.Runtime.CompilerServices.CallerFilePath] string filePath = "", [System.Runtime.CompilerServices.CallerLineNumber]int lineNumber = 0) { return MapCore(endpoints, pattern, handler, PutVerb, filePath, lineNumber); } /// /// Adds a to the that matches HTTP POST requests /// for the specified pattern. /// /// The to add the route to. /// The route pattern. /// The delegate executed when the endpoint is matched. /// A that can be used to further customize the endpoint. internal static Microsoft.AspNetCore.Builder.RouteHandlerBuilder MapPost(this Microsoft.AspNetCore.Routing.IEndpointRouteBuilder endpoints, string pattern, System.Func> handler, [System.Runtime.CompilerServices.CallerFilePath] string filePath = "", [System.Runtime.CompilerServices.CallerLineNumber]int lineNumber = 0) { return MapCore(endpoints, pattern, handler, PostVerb, filePath, lineNumber); } /// /// Adds a to the that matches HTTP DELETE requests /// for the specified pattern. /// /// The to add the route to. /// The route pattern. /// The delegate executed when the endpoint is matched. /// A that can be used to further customize the endpoint. internal static Microsoft.AspNetCore.Builder.RouteHandlerBuilder MapDelete(this Microsoft.AspNetCore.Routing.IEndpointRouteBuilder endpoints, string pattern, System.Func> handler, [System.Runtime.CompilerServices.CallerFilePath] string filePath = "", [System.Runtime.CompilerServices.CallerLineNumber]int lineNumber = 0) { return MapCore(endpoints, pattern, handler, DeleteVerb, filePath, lineNumber); } /// /// Adds a to the that matches HTTP GET requests /// for the specified pattern. /// /// The to add the route to. /// The route pattern. /// The delegate executed when the endpoint is matched. /// A that can be used to further customize the endpoint. internal static Microsoft.AspNetCore.Builder.RouteHandlerBuilder MapGet(this Microsoft.AspNetCore.Routing.IEndpointRouteBuilder endpoints, string pattern, System.Func handler, [System.Runtime.CompilerServices.CallerFilePath] string filePath = "", [System.Runtime.CompilerServices.CallerLineNumber]int lineNumber = 0) { return MapCore(endpoints, pattern, handler, GetVerb, filePath, lineNumber); } /// /// Adds a to the that matches HTTP GET requests /// for the specified pattern. /// /// The to add the route to. /// The route pattern. /// The delegate executed when the endpoint is matched. /// A that can be used to further customize the endpoint. internal static Microsoft.AspNetCore.Builder.RouteHandlerBuilder MapGet(this Microsoft.AspNetCore.Routing.IEndpointRouteBuilder endpoints, string pattern, System.Func handler, [System.Runtime.CompilerServices.CallerFilePath] string filePath = "", [System.Runtime.CompilerServices.CallerLineNumber]int lineNumber = 0) { return MapCore(endpoints, pattern, handler, GetVerb, filePath, lineNumber); } /// /// Adds a to the that matches HTTP GET requests /// for the specified pattern. /// /// The to add the route to. /// The route pattern. /// The delegate executed when the endpoint is matched. /// A that can be used to further customize the endpoint. internal static Microsoft.AspNetCore.Builder.RouteHandlerBuilder MapGet(this Microsoft.AspNetCore.Routing.IEndpointRouteBuilder endpoints, string pattern, System.Func handler, [System.Runtime.CompilerServices.CallerFilePath] string filePath = "", [System.Runtime.CompilerServices.CallerLineNumber]int lineNumber = 0) { return MapCore(endpoints, pattern, handler, GetVerb, filePath, lineNumber); } /// /// Adds a to the that matches HTTP GET requests /// for the specified pattern. /// /// The to add the route to. /// The route pattern. /// The delegate executed when the endpoint is matched. /// A that can be used to further customize the endpoint. internal static Microsoft.AspNetCore.Builder.RouteHandlerBuilder MapGet(this Microsoft.AspNetCore.Routing.IEndpointRouteBuilder endpoints, string pattern, System.Func handler, [System.Runtime.CompilerServices.CallerFilePath] string filePath = "", [System.Runtime.CompilerServices.CallerLineNumber]int lineNumber = 0) { return MapCore(endpoints, pattern, handler, GetVerb, filePath, lineNumber); } /// /// Adds a to the that matches HTTP GET requests /// for the specified pattern. /// /// The to add the route to. /// The route pattern. /// The delegate executed when the endpoint is matched. /// A that can be used to further customize the endpoint. internal static Microsoft.AspNetCore.Builder.RouteHandlerBuilder MapGet(this Microsoft.AspNetCore.Routing.IEndpointRouteBuilder endpoints, string pattern, System.Func handler, [System.Runtime.CompilerServices.CallerFilePath] string filePath = "", [System.Runtime.CompilerServices.CallerLineNumber]int lineNumber = 0) { return MapCore(endpoints, pattern, handler, GetVerb, filePath, lineNumber); } /// /// Adds a to the that matches HTTP POST requests /// for the specified pattern. /// /// The to add the route to. /// The route pattern. /// The delegate executed when the endpoint is matched. /// A that can be used to further customize the endpoint. internal static Microsoft.AspNetCore.Builder.RouteHandlerBuilder MapPost(this Microsoft.AspNetCore.Routing.IEndpointRouteBuilder endpoints, string pattern, System.Func handler, [System.Runtime.CompilerServices.CallerFilePath] string filePath = "", [System.Runtime.CompilerServices.CallerLineNumber]int lineNumber = 0) { return MapCore(endpoints, pattern, handler, PostVerb, filePath, lineNumber); } /// /// Adds a to the that matches HTTP POST requests /// for the specified pattern. /// /// The to add the route to. /// The route pattern. /// The delegate executed when the endpoint is matched. /// A that can be used to further customize the endpoint. internal static Microsoft.AspNetCore.Builder.RouteHandlerBuilder MapPost(this Microsoft.AspNetCore.Routing.IEndpointRouteBuilder endpoints, string pattern, System.Func handler, [System.Runtime.CompilerServices.CallerFilePath] string filePath = "", [System.Runtime.CompilerServices.CallerLineNumber]int lineNumber = 0) { return MapCore(endpoints, pattern, handler, PostVerb, filePath, lineNumber); } /// /// Adds a to the that matches HTTP POST requests /// for the specified pattern. /// /// The to add the route to. /// The route pattern. /// The delegate executed when the endpoint is matched. /// A that can be used to further customize the endpoint. internal static Microsoft.AspNetCore.Builder.RouteHandlerBuilder MapPost(this Microsoft.AspNetCore.Routing.IEndpointRouteBuilder endpoints, string pattern, System.Action handler, [System.Runtime.CompilerServices.CallerFilePath] string filePath = "", [System.Runtime.CompilerServices.CallerLineNumber]int lineNumber = 0) { return MapCore(endpoints, pattern, handler, PostVerb, filePath, lineNumber); } /// /// Adds a to the that matches HTTP POST requests /// for the specified pattern. /// /// The to add the route to. /// The route pattern. /// The delegate executed when the endpoint is matched. /// A that can be used to further customize the endpoint. internal static Microsoft.AspNetCore.Builder.RouteHandlerBuilder MapPost(this Microsoft.AspNetCore.Routing.IEndpointRouteBuilder endpoints, string pattern, System.Func handler, [System.Runtime.CompilerServices.CallerFilePath] string filePath = "", [System.Runtime.CompilerServices.CallerLineNumber]int lineNumber = 0) { return MapCore(endpoints, pattern, handler, PostVerb, filePath, lineNumber); } /// /// Adds a to the that matches HTTP GET requests /// for the specified pattern. /// /// The to add the route to. /// The route pattern. /// The delegate executed when the endpoint is matched. /// A that can be used to further customize the endpoint. internal static Microsoft.AspNetCore.Builder.RouteHandlerBuilder MapGet(this Microsoft.AspNetCore.Routing.IEndpointRouteBuilder endpoints, string pattern, System.Func handler, [System.Runtime.CompilerServices.CallerFilePath] string filePath = "", [System.Runtime.CompilerServices.CallerLineNumber]int lineNumber = 0) { return MapCore(endpoints, pattern, handler, GetVerb, filePath, lineNumber); } /// /// Adds a to the that matches HTTP POST requests /// for the specified pattern. /// /// The to add the route to. /// The route pattern. /// The delegate executed when the endpoint is matched. /// A that can be used to further customize the endpoint. internal static Microsoft.AspNetCore.Builder.RouteHandlerBuilder MapPost(this Microsoft.AspNetCore.Routing.IEndpointRouteBuilder endpoints, string pattern, System.Func handler, [System.Runtime.CompilerServices.CallerFilePath] string filePath = "", [System.Runtime.CompilerServices.CallerLineNumber]int lineNumber = 0) { return MapCore(endpoints, pattern, handler, PostVerb, filePath, lineNumber); } /// /// Adds a to the that matches HTTP POST requests /// for the specified pattern. /// /// The to add the route to. /// The route pattern. /// The delegate executed when the endpoint is matched. /// A that can be used to further customize the endpoint. internal static Microsoft.AspNetCore.Builder.RouteHandlerBuilder MapPost(this Microsoft.AspNetCore.Routing.IEndpointRouteBuilder endpoints, string pattern, System.Func, string> handler, [System.Runtime.CompilerServices.CallerFilePath] string filePath = "", [System.Runtime.CompilerServices.CallerLineNumber]int lineNumber = 0) { return MapCore(endpoints, pattern, handler, PostVerb, filePath, lineNumber); } /// /// Adds a to the that matches HTTP POST requests /// for the specified pattern. /// /// The to add the route to. /// The route pattern. /// The delegate executed when the endpoint is matched. /// A that can be used to further customize the endpoint. internal static Microsoft.AspNetCore.Builder.RouteHandlerBuilder MapPost(this Microsoft.AspNetCore.Routing.IEndpointRouteBuilder endpoints, string pattern, System.Func, Microsoft.AspNetCore.Http.IResult> handler, [System.Runtime.CompilerServices.CallerFilePath] string filePath = "", [System.Runtime.CompilerServices.CallerLineNumber]int lineNumber = 0) { return MapCore(endpoints, pattern, handler, PostVerb, filePath, lineNumber); } /// /// Adds a to the that matches HTTP GET requests /// for the specified pattern. /// /// The to add the route to. /// The route pattern. /// The delegate executed when the endpoint is matched. /// A that can be used to further customize the endpoint. internal static Microsoft.AspNetCore.Builder.RouteHandlerBuilder MapGet(this Microsoft.AspNetCore.Routing.IEndpointRouteBuilder endpoints, string pattern, System.Func handler, [System.Runtime.CompilerServices.CallerFilePath] string filePath = "", [System.Runtime.CompilerServices.CallerLineNumber]int lineNumber = 0) { return MapCore(endpoints, pattern, handler, GetVerb, filePath, lineNumber); } /// /// Adds a to the that matches HTTP requests /// for the specified pattern. /// /// The to add the route to. /// The route pattern. /// The delegate executed when the endpoint is matched. /// A that can be used to further customize the endpoint. internal static Microsoft.AspNetCore.Builder.RouteHandlerBuilder Map(this Microsoft.AspNetCore.Routing.IEndpointRouteBuilder endpoints, string pattern, System.Func handler, [System.Runtime.CompilerServices.CallerFilePath] string filePath = "", [System.Runtime.CompilerServices.CallerLineNumber]int lineNumber = 0) { return MapCore(endpoints, pattern, handler, null, filePath, lineNumber); } /// /// Adds a to the that matches HTTP POST requests /// for the specified pattern. /// /// The to add the route to. /// The route pattern. /// The delegate executed when the endpoint is matched. /// A that can be used to further customize the endpoint. internal static Microsoft.AspNetCore.Builder.RouteHandlerBuilder MapPost(this Microsoft.AspNetCore.Routing.IEndpointRouteBuilder endpoints, string pattern, System.Func handler, [System.Runtime.CompilerServices.CallerFilePath] string filePath = "", [System.Runtime.CompilerServices.CallerLineNumber]int lineNumber = 0) { return MapCore(endpoints, pattern, handler, PostVerb, filePath, lineNumber); } /// /// Adds a to the that matches HTTP POST requests /// for the specified pattern. /// /// The to add the route to. /// The route pattern. /// The delegate executed when the endpoint is matched. /// A that can be used to further customize the endpoint. internal static Microsoft.AspNetCore.Builder.RouteHandlerBuilder MapPost(this Microsoft.AspNetCore.Routing.IEndpointRouteBuilder endpoints, string pattern, System.Func handler, [System.Runtime.CompilerServices.CallerFilePath] string filePath = "", [System.Runtime.CompilerServices.CallerLineNumber]int lineNumber = 0) { return MapCore(endpoints, pattern, handler, PostVerb, filePath, lineNumber); } /// /// Adds a to the that matches HTTP PATCH requests /// for the specified pattern. /// /// The to add the route to. /// The route pattern. /// The delegate executed when the endpoint is matched. /// A that can be used to further customize the endpoint. internal static Microsoft.AspNetCore.Builder.RouteHandlerBuilder MapPatch(this Microsoft.AspNetCore.Routing.IEndpointRouteBuilder endpoints, string pattern, System.Func handler, [System.Runtime.CompilerServices.CallerFilePath] string filePath = "", [System.Runtime.CompilerServices.CallerLineNumber]int lineNumber = 0) { return MapCore(endpoints, pattern, handler, PatchVerb, filePath, lineNumber); } /// /// Adds a to the that matches HTTP GET requests /// for the specified pattern. /// /// The to add the route to. /// The route pattern. /// The delegate executed when the endpoint is matched. /// A that can be used to further customize the endpoint. internal static Microsoft.AspNetCore.Builder.RouteHandlerBuilder MapGet(this Microsoft.AspNetCore.Routing.IEndpointRouteBuilder endpoints, string pattern, System.Func handler, [System.Runtime.CompilerServices.CallerFilePath] string filePath = "", [System.Runtime.CompilerServices.CallerLineNumber]int lineNumber = 0) { return MapCore(endpoints, pattern, handler, GetVerb, filePath, lineNumber); } /// /// Adds a to the that matches HTTP GET requests /// for the specified pattern. /// /// The to add the route to. /// The route pattern. /// The delegate executed when the endpoint is matched. /// A that can be used to further customize the endpoint. internal static Microsoft.AspNetCore.Builder.RouteHandlerBuilder MapGet(this Microsoft.AspNetCore.Routing.IEndpointRouteBuilder endpoints, string pattern, System.Func handler, [System.Runtime.CompilerServices.CallerFilePath] string filePath = "", [System.Runtime.CompilerServices.CallerLineNumber]int lineNumber = 0) { return MapCore(endpoints, pattern, handler, GetVerb, filePath, lineNumber); } /// /// Adds a to the that matches HTTP GET requests /// for the specified pattern. /// /// The to add the route to. /// The route pattern. /// The delegate executed when the endpoint is matched. /// A that can be used to further customize the endpoint. internal static Microsoft.AspNetCore.Builder.RouteHandlerBuilder MapGet(this Microsoft.AspNetCore.Routing.IEndpointRouteBuilder endpoints, string pattern, System.Func handler, [System.Runtime.CompilerServices.CallerFilePath] string filePath = "", [System.Runtime.CompilerServices.CallerLineNumber]int lineNumber = 0) { return MapCore(endpoints, pattern, handler, GetVerb, filePath, lineNumber); } /// /// Adds a to the that matches HTTP GET requests /// for the specified pattern. /// /// The to add the route to. /// The route pattern. /// The delegate executed when the endpoint is matched. /// A that can be used to further customize the endpoint. internal static Microsoft.AspNetCore.Builder.RouteHandlerBuilder MapGet(this Microsoft.AspNetCore.Routing.IEndpointRouteBuilder endpoints, string pattern, System.Func handler, [System.Runtime.CompilerServices.CallerFilePath] string filePath = "", [System.Runtime.CompilerServices.CallerLineNumber]int lineNumber = 0) { return MapCore(endpoints, pattern, handler, GetVerb, filePath, lineNumber); } /// /// Adds a to the that matches HTTP GET requests /// for the specified pattern. /// /// The to add the route to. /// The route pattern. /// The delegate executed when the endpoint is matched. /// A that can be used to further customize the endpoint. internal static Microsoft.AspNetCore.Builder.RouteHandlerBuilder MapGet(this Microsoft.AspNetCore.Routing.IEndpointRouteBuilder endpoints, string pattern, System.Func handler, [System.Runtime.CompilerServices.CallerFilePath] string filePath = "", [System.Runtime.CompilerServices.CallerLineNumber]int lineNumber = 0) { return MapCore(endpoints, pattern, handler, GetVerb, filePath, lineNumber); } /// /// Adds a to the that matches HTTP requests /// for the specified pattern. /// /// The to add the route to. /// The route pattern. /// The delegate executed when the endpoint is matched. /// A that can be used to further customize the endpoint. internal static Microsoft.AspNetCore.Builder.RouteHandlerBuilder Map(this Microsoft.AspNetCore.Routing.IEndpointRouteBuilder endpoints, string pattern, System.Func handler, [System.Runtime.CompilerServices.CallerFilePath] string filePath = "", [System.Runtime.CompilerServices.CallerLineNumber]int lineNumber = 0) { return MapCore(endpoints, pattern, handler, null, filePath, lineNumber); } /// /// Adds a to the that matches HTTP requests /// for the specified pattern. /// /// The to add the route to. /// The route pattern. /// The delegate executed when the endpoint is matched. /// A that can be used to further customize the endpoint. internal static Microsoft.AspNetCore.Builder.RouteHandlerBuilder Map(this Microsoft.AspNetCore.Routing.IEndpointRouteBuilder endpoints, string pattern, System.Action handler, [System.Runtime.CompilerServices.CallerFilePath] string filePath = "", [System.Runtime.CompilerServices.CallerLineNumber]int lineNumber = 0) { return MapCore(endpoints, pattern, handler, null, filePath, lineNumber); } /// /// Adds a to the that matches HTTP PUT requests /// for the specified pattern. /// /// The to add the route to. /// The route pattern. /// The delegate executed when the endpoint is matched. /// A that can be used to further customize the endpoint. internal static Microsoft.AspNetCore.Builder.RouteHandlerBuilder MapPut(this Microsoft.AspNetCore.Routing.IEndpointRouteBuilder endpoints, string pattern, System.Func handler, [System.Runtime.CompilerServices.CallerFilePath] string filePath = "", [System.Runtime.CompilerServices.CallerLineNumber]int lineNumber = 0) { return MapCore(endpoints, pattern, handler, PutVerb, filePath, lineNumber); } /// /// Adds a to the that matches HTTP PUT requests /// for the specified pattern. /// /// The to add the route to. /// The route pattern. /// The delegate executed when the endpoint is matched. /// A that can be used to further customize the endpoint. internal static Microsoft.AspNetCore.Builder.RouteHandlerBuilder MapPut(this Microsoft.AspNetCore.Routing.IEndpointRouteBuilder endpoints, string pattern, System.Action handler, [System.Runtime.CompilerServices.CallerFilePath] string filePath = "", [System.Runtime.CompilerServices.CallerLineNumber]int lineNumber = 0) { return MapCore(endpoints, pattern, handler, PutVerb, filePath, lineNumber); } /// /// Adds a to the that matches HTTP POST requests /// for the specified pattern. /// /// The to add the route to. /// The route pattern. /// The delegate executed when the endpoint is matched. /// A that can be used to further customize the endpoint. internal static Microsoft.AspNetCore.Builder.RouteHandlerBuilder MapPost(this Microsoft.AspNetCore.Routing.IEndpointRouteBuilder endpoints, string pattern, System.Func handler, [System.Runtime.CompilerServices.CallerFilePath] string filePath = "", [System.Runtime.CompilerServices.CallerLineNumber]int lineNumber = 0) { return MapCore(endpoints, pattern, handler, PostVerb, filePath, lineNumber); } /// /// Adds a to the that matches HTTP POST requests /// for the specified pattern. /// /// The to add the route to. /// The route pattern. /// The delegate executed when the endpoint is matched. /// A that can be used to further customize the endpoint. internal static Microsoft.AspNetCore.Builder.RouteHandlerBuilder MapPost(this Microsoft.AspNetCore.Routing.IEndpointRouteBuilder endpoints, string pattern, System.Action handler, [System.Runtime.CompilerServices.CallerFilePath] string filePath = "", [System.Runtime.CompilerServices.CallerLineNumber]int lineNumber = 0) { return MapCore(endpoints, pattern, handler, PostVerb, filePath, lineNumber); } /// /// Adds a to the that matches HTTP DELETE requests /// for the specified pattern. /// /// The to add the route to. /// The route pattern. /// The delegate executed when the endpoint is matched. /// A that can be used to further customize the endpoint. internal static Microsoft.AspNetCore.Builder.RouteHandlerBuilder MapDelete(this Microsoft.AspNetCore.Routing.IEndpointRouteBuilder endpoints, string pattern, System.Func handler, [System.Runtime.CompilerServices.CallerFilePath] string filePath = "", [System.Runtime.CompilerServices.CallerLineNumber]int lineNumber = 0) { return MapCore(endpoints, pattern, handler, DeleteVerb, filePath, lineNumber); } /// /// Adds a to the that matches HTTP DELETE requests /// for the specified pattern. /// /// The to add the route to. /// The route pattern. /// The delegate executed when the endpoint is matched. /// A that can be used to further customize the endpoint. internal static Microsoft.AspNetCore.Builder.RouteHandlerBuilder MapDelete(this Microsoft.AspNetCore.Routing.IEndpointRouteBuilder endpoints, string pattern, System.Action handler, [System.Runtime.CompilerServices.CallerFilePath] string filePath = "", [System.Runtime.CompilerServices.CallerLineNumber]int lineNumber = 0) { return MapCore(endpoints, pattern, handler, DeleteVerb, filePath, lineNumber); } /// /// Adds a to the that matches HTTP PATCH requests /// for the specified pattern. /// /// The to add the route to. /// The route pattern. /// The delegate executed when the endpoint is matched. /// A that can be used to further customize the endpoint. internal static Microsoft.AspNetCore.Builder.RouteHandlerBuilder MapPatch(this Microsoft.AspNetCore.Routing.IEndpointRouteBuilder endpoints, string pattern, System.Func handler, [System.Runtime.CompilerServices.CallerFilePath] string filePath = "", [System.Runtime.CompilerServices.CallerLineNumber]int lineNumber = 0) { return MapCore(endpoints, pattern, handler, PatchVerb, filePath, lineNumber); } /// /// Adds a to the that matches HTTP PATCH requests /// for the specified pattern. /// /// The to add the route to. /// The route pattern. /// The delegate executed when the endpoint is matched. /// A that can be used to further customize the endpoint. internal static Microsoft.AspNetCore.Builder.RouteHandlerBuilder MapPatch(this Microsoft.AspNetCore.Routing.IEndpointRouteBuilder endpoints, string pattern, System.Action handler, [System.Runtime.CompilerServices.CallerFilePath] string filePath = "", [System.Runtime.CompilerServices.CallerLineNumber]int lineNumber = 0) { return MapCore(endpoints, pattern, handler, PatchVerb, filePath, lineNumber); } /// /// Adds a to the that matches HTTP GET requests /// for the specified pattern. /// /// The to add the route to. /// The route pattern. /// The delegate executed when the endpoint is matched. /// A that can be used to further customize the endpoint. internal static Microsoft.AspNetCore.Builder.RouteHandlerBuilder MapGet(this Microsoft.AspNetCore.Routing.IEndpointRouteBuilder endpoints, string pattern, System.Func handler, [System.Runtime.CompilerServices.CallerFilePath] string filePath = "", [System.Runtime.CompilerServices.CallerLineNumber]int lineNumber = 0) { return MapCore(endpoints, pattern, handler, GetVerb, filePath, lineNumber); } /// /// Adds a to the that matches HTTP GET requests /// for the specified pattern. /// /// The to add the route to. /// The route pattern. /// The delegate executed when the endpoint is matched. /// A that can be used to further customize the endpoint. internal static Microsoft.AspNetCore.Builder.RouteHandlerBuilder MapGet(this Microsoft.AspNetCore.Routing.IEndpointRouteBuilder endpoints, string pattern, System.Func handler, [System.Runtime.CompilerServices.CallerFilePath] string filePath = "", [System.Runtime.CompilerServices.CallerLineNumber]int lineNumber = 0) { return MapCore(endpoints, pattern, handler, GetVerb, filePath, lineNumber); } private static Microsoft.AspNetCore.Builder.RouteHandlerBuilder MapCore( this Microsoft.AspNetCore.Routing.IEndpointRouteBuilder routes, string pattern, System.Delegate handler, IEnumerable httpMethods, string filePath, int lineNumber) { var (populate, factory) = GenericThunks.map[(filePath, lineNumber)]; return GetOrAddRouteEndpointDataSource(routes).AddRouteHandler(RoutePatternFactory.Parse(pattern), handler, httpMethods, isFallback: false, populate, factory); } private static Microsoft.AspNetCore.Builder.RouteHandlerBuilder MapCore( this Microsoft.AspNetCore.Routing.IEndpointRouteBuilder routes, string pattern, System.Delegate handler, IEnumerable httpMethods, string filePath, int lineNumber) { var (populate, factory) = map[(filePath, lineNumber)]; return GetOrAddRouteEndpointDataSource(routes).AddRouteHandler(RoutePatternFactory.Parse(pattern), handler, httpMethods, isFallback: false, populate, factory); } private static SourceGeneratedRouteEndpointDataSource GetOrAddRouteEndpointDataSource(IEndpointRouteBuilder endpoints) { SourceGeneratedRouteEndpointDataSource routeEndpointDataSource = null; foreach (var dataSource in endpoints.DataSources) { if (dataSource is SourceGeneratedRouteEndpointDataSource foundDataSource) { routeEndpointDataSource = foundDataSource; break; } } if (routeEndpointDataSource is null) { routeEndpointDataSource = new SourceGeneratedRouteEndpointDataSource(endpoints.ServiceProvider); endpoints.DataSources.Add(routeEndpointDataSource); } return routeEndpointDataSource; } private static EndpointFilterDelegate BuildFilterDelegate(EndpointFilterDelegate filteredInvocation, EndpointBuilder builder, System.Reflection.MethodInfo mi) { var routeHandlerFilters = builder.FilterFactories; var context0 = new EndpointFilterFactoryContext { MethodInfo = mi, ApplicationServices = builder.ApplicationServices, }; var initialFilteredInvocation = filteredInvocation; for (var i = routeHandlerFilters.Count - 1; i >= 0; i--) { var filterFactory = routeHandlerFilters[i]; filteredInvocation = filterFactory(context0, filteredInvocation); } return filteredInvocation; } private static void PopulateMetadata(System.Reflection.MethodInfo method, EndpointBuilder builder) where T : Microsoft.AspNetCore.Http.Metadata.IEndpointMetadataProvider { T.PopulateMetadata(method, builder); } private static void PopulateMetadata(System.Reflection.ParameterInfo parameter, EndpointBuilder builder) where T : Microsoft.AspNetCore.Http.Metadata.IEndpointParameterMetadataProvider { T.PopulateMetadata(parameter, builder); } private static Task ExecuteObjectResult(object obj, HttpContext httpContext) { if (obj is IResult r) { return r.ExecuteAsync(httpContext); } else if (obj is string s) { return httpContext.Response.WriteAsync(s); } else { return httpContext.Response.WriteAsJsonAsync(obj); } } private static Microsoft.Extensions.Primitives.StringValues ResolveByQuery(HttpContext context, string key) => context.Request.Query[key]; private static Microsoft.Extensions.Primitives.StringValues ResolveByRoute(HttpContext context, string key) => context.Request.RouteValues[key]?.ToString(); private static ValueTask ResolveService(HttpContext httpContext) => new ValueTask(httpContext.RequestServices.GetRequiredService()); private static async ValueTask ResolveBody(HttpContext httpContext) { var feature = httpContext.Features.Get(); if (feature?.CanHaveBody == true) { if (!httpContext.Request.HasJsonContentType()) { httpContext.Response.StatusCode = StatusCodes.Status415UnsupportedMediaType; return default; } try { return await httpContext.Request.ReadFromJsonAsync(); } catch (IOException) { return default; } catch (System.Text.Json.JsonException) { httpContext.Response.StatusCode = StatusCodes.Status400BadRequest; return default; } } return default; } private sealed class ResponseTypeMetadata : Microsoft.AspNetCore.Http.Metadata.IProducesResponseTypeMetadata { public Type Type { get; set; } = typeof(void); public int StatusCode { get; set; } = 200; public IEnumerable ContentTypes { get; init; } = Enumerable.Empty(); public static ResponseTypeMetadata Create(string contentType, Type type = null) { return new ResponseTypeMetadata { ContentTypes = new[] { contentType }, Type = type }; } public static ResponseTypeMetadata Create(int statusCode) { return new ResponseTypeMetadata { StatusCode = statusCode }; } } private sealed class SourceGeneratedRouteEndpointDataSource : EndpointDataSource { private readonly List _routeEntries = new(); private readonly IServiceProvider _applicationServices; public SourceGeneratedRouteEndpointDataSource(IServiceProvider applicationServices) { _applicationServices = applicationServices; } public RouteHandlerBuilder AddRouteHandler( RoutePattern pattern, Delegate routeHandler, IEnumerable httpMethods, bool isFallback, MetadataPopulator metadataPopulator, RequestDelegateFactoryFunc requestDelegateFactoryFunc) { var conventions = new ThrowOnAddAfterEndpointBuiltConventionCollection(); var finallyConventions = new ThrowOnAddAfterEndpointBuiltConventionCollection(); var routeAttributes = RouteAttributes.RouteHandler; if (isFallback) { routeAttributes |= RouteAttributes.Fallback; } _routeEntries.Add(new() { RoutePattern = pattern, RouteHandler = routeHandler, HttpMethods = httpMethods, RouteAttributes = routeAttributes, Conventions = conventions, FinallyConventions = finallyConventions, RequestDelegateFactory = requestDelegateFactoryFunc, MetadataPopulator = metadataPopulator, }); return new RouteHandlerBuilder(new[] { new ConventionBuilder(conventions, finallyConventions) }); } public override IReadOnlyList Endpoints { get { var endpoints = new RouteEndpoint[_routeEntries.Count]; for (int i = 0; i < _routeEntries.Count; i++) { endpoints[i] = (RouteEndpoint)CreateRouteEndpointBuilder(_routeEntries[i]).Build(); } return endpoints; } } public override IReadOnlyList GetGroupedEndpoints(RouteGroupContext context) { var endpoints = new RouteEndpoint[_routeEntries.Count]; for (int i = 0; i < _routeEntries.Count; i++) { endpoints[i] = (RouteEndpoint)CreateRouteEndpointBuilder(_routeEntries[i], context.Prefix, context.Conventions, context.FinallyConventions).Build(); } return endpoints; } public override IChangeToken GetChangeToken() => NullChangeToken.Singleton; private RouteEndpointBuilder CreateRouteEndpointBuilder( RouteEntry entry, RoutePattern groupPrefix = null, IReadOnlyList> groupConventions = null, IReadOnlyList> groupFinallyConventions = null) { var pattern = RoutePatternFactory.Combine(groupPrefix, entry.RoutePattern); var handler = entry.RouteHandler; var isRouteHandler = (entry.RouteAttributes & RouteAttributes.RouteHandler) == RouteAttributes.RouteHandler; var isFallback = (entry.RouteAttributes & RouteAttributes.Fallback) == RouteAttributes.Fallback; var order = isFallback ? int.MaxValue : 0; var displayName = pattern.RawText ?? pattern.ToString(); if (entry.HttpMethods is not null) { // Prepends the HTTP method to the DisplayName produced with pattern + method name displayName = $"HTTP: {string.Join(", ", entry.HttpMethods)} {displayName}"; } if (isFallback) { displayName = $"Fallback {displayName}"; } // If we're not a route handler, we started with a fully realized (although unfiltered) RequestDelegate, so we can just redirect to that // while running any conventions. We'll put the original back if it remains unfiltered right before building the endpoint. RequestDelegate factoryCreatedRequestDelegate = null; // Let existing conventions capture and call into builder.RequestDelegate as long as they do so after it has been created. RequestDelegate redirectRequestDelegate = context => { if (factoryCreatedRequestDelegate is null) { throw new InvalidOperationException("Resources.RouteEndpointDataSource_RequestDelegateCannotBeCalledBeforeBuild"); } return factoryCreatedRequestDelegate(context); }; // Add MethodInfo and HttpMethodMetadata (if any) as first metadata items as they are intrinsic to the route much like // the pattern or default display name. This gives visibility to conventions like WithOpenApi() to intrinsic route details // (namely the MethodInfo) even when applied early as group conventions. RouteEndpointBuilder builder = new(redirectRequestDelegate, pattern, order) { DisplayName = displayName, ApplicationServices = _applicationServices, }; if (isRouteHandler) { builder.Metadata.Add(handler.Method); } if (entry.HttpMethods is not null) { builder.Metadata.Add(new HttpMethodMetadata(entry.HttpMethods)); } // Apply group conventions before entry-specific conventions added to the RouteHandlerBuilder. if (groupConventions is not null) { foreach (var groupConvention in groupConventions) { groupConvention(builder); } } // Any metadata inferred directly inferred by RDF or indirectly inferred via IEndpoint(Parameter)MetadataProviders are // considered less specific than method-level attributes and conventions but more specific than group conventions // so inferred metadata gets added in between these. If group conventions need to override inferred metadata, // they can do so via IEndpointConventionBuilder.Finally like the do to override any other entry-specific metadata. if (isRouteHandler) { entry.MetadataPopulator(entry.RouteHandler, builder); } // Add delegate attributes as metadata before entry-specific conventions but after group conventions. var attributes = handler.Method.GetCustomAttributes(); if (attributes is not null) { foreach (var attribute in attributes) { builder.Metadata.Add(attribute); } } entry.Conventions.IsReadOnly = true; foreach (var entrySpecificConvention in entry.Conventions) { entrySpecificConvention(builder); } // If no convention has modified builder.RequestDelegate, we can use the RequestDelegate returned by the RequestDelegateFactory directly. var conventionOverriddenRequestDelegate = ReferenceEquals(builder.RequestDelegate, redirectRequestDelegate) ? null : builder.RequestDelegate; if (isRouteHandler || builder.FilterFactories.Count > 0) { factoryCreatedRequestDelegate = entry.RequestDelegateFactory(entry.RouteHandler, builder); } Debug.Assert(factoryCreatedRequestDelegate is not null); // Use the overridden RequestDelegate if it exists. If the overridden RequestDelegate is merely wrapping the final RequestDelegate, // it will still work because of the redirectRequestDelegate. builder.RequestDelegate = conventionOverriddenRequestDelegate ?? factoryCreatedRequestDelegate; entry.FinallyConventions.IsReadOnly = true; foreach (var entryFinallyConvention in entry.FinallyConventions) { entryFinallyConvention(builder); } if (groupFinallyConventions is not null) { // Group conventions are ordered by the RouteGroupBuilder before // being provided here. foreach (var groupFinallyConvention in groupFinallyConventions) { groupFinallyConvention(builder); } } return builder; } private struct RouteEntry { public MetadataPopulator MetadataPopulator { get; init; } public RequestDelegateFactoryFunc RequestDelegateFactory { get; init; } public RoutePattern RoutePattern { get; init; } public Delegate RouteHandler { get; init; } public IEnumerable HttpMethods { get; init; } public RouteAttributes RouteAttributes { get; init; } public ThrowOnAddAfterEndpointBuiltConventionCollection Conventions { get; init; } public ThrowOnAddAfterEndpointBuiltConventionCollection FinallyConventions { get; init; } } [Flags] private enum RouteAttributes { // The endpoint was defined by a RequestDelegate, RequestDelegateFactory.Create() should be skipped unless there are endpoint filters. None = 0, // This was added as Delegate route handler, so RequestDelegateFactory.Create() should always be called. RouteHandler = 1, // This was added by MapFallback. Fallback = 2, } // This private class is only exposed to internal code via ICollection> in RouteEndpointBuilder where only Add is called. private sealed class ThrowOnAddAfterEndpointBuiltConventionCollection : List>, ICollection> { // We throw if someone tries to add conventions to the RouteEntry after endpoints have already been resolved meaning the conventions // will not be observed given RouteEndpointDataSource is not meant to be dynamic and uses NullChangeToken.Singleton. public bool IsReadOnly { get; set; } void ICollection>.Add(Action convention) { if (IsReadOnly) { throw new InvalidOperationException("Resources.RouteEndpointDataSource_ConventionsCannotBeModifiedAfterBuild"); } Add(convention); } } private class ConventionBuilder : IEndpointConventionBuilder { private readonly ICollection> _conventions; private readonly ICollection> _finallyConventions; public ConventionBuilder(ICollection> conventions, ICollection> finallyConventions) { _conventions = conventions; _finallyConventions = finallyConventions; } /// /// Adds the specified convention to the builder. Conventions are used to customize instances. /// /// The convention to add to the builder. public void Add(Action convention) { _conventions.Add(convention); } public void Finally(Action finalConvention) { _finallyConventions.Add(finalConvention); } } } } #endif ================================================ FILE: README.md ================================================ ## Source generator for minimal APIs This source generator should make your ASP.NET Core minimal API application trim and AOT friendly. ## Using CI Builds To use CI builds add the following nuget feed: ```xml ``` See the list of [versions](https://f.feedz.io/davidfowl/ucontroller/nuget/v3/packages/ucontroller/index.json) ================================================ FILE: nuget.config ================================================ ================================================ FILE: samples/.vscode/launch.json ================================================ { "version": "0.2.0", "configurations": [ { // Use IntelliSense to find out which attributes exist for C# debugging // Use hover for the description of the existing attributes // For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md "name": ".NET Core Launch (web)", "type": "coreclr", "request": "launch", "preLaunchTask": "build", // If you have changed target frameworks, make sure to update the program path. "program": "${workspaceFolder}/bin/Debug/net7.0/Sample.dll", "args": [], "cwd": "${workspaceFolder}", "stopAtEntry": false, // Enable launching a web browser when ASP.NET Core starts. For more information: https://aka.ms/VSCode-CS-LaunchJson-WebBrowser "serverReadyAction": { "action": "openExternally", "pattern": "\\bNow listening on:\\s+(https?://\\S+)" }, "env": { "ASPNETCORE_ENVIRONMENT": "Development" }, "sourceFileMap": { "/Views": "${workspaceFolder}/Views" } }, { "name": ".NET Core Attach", "type": "coreclr", "request": "attach" } ] } ================================================ FILE: samples/.vscode/tasks.json ================================================ { "version": "2.0.0", "tasks": [ { "label": "build", "command": "dotnet", "type": "process", "args": [ "build", "${workspaceFolder}/Sample.csproj", "/property:GenerateFullPaths=true", "/consoleloggerparameters:NoSummary" ], "problemMatcher": "$msCompile" }, { "label": "publish", "command": "dotnet", "type": "process", "args": [ "publish", "${workspaceFolder}/Sample.csproj", "/property:GenerateFullPaths=true", "/consoleloggerparameters:NoSummary" ], "problemMatcher": "$msCompile" }, { "label": "watch", "command": "dotnet", "type": "process", "args": [ "watch", "run", "--project", "${workspaceFolder}/Sample.csproj" ], "problemMatcher": "$msCompile" } ] } ================================================ FILE: samples/MapTodos.cs ================================================ // using Microsoft.EntityFrameworkCore; public static class TodoEndpoints { public static void MapTodoEndpoints(this IEndpointRouteBuilder routes) { var group = routes.MapGroup("/api/Todo"); // group.WithOpenApi(); group.MapGet("/", async (TodoDbContext db) => { return await db.Todos.ToListAsync(); }) .WithTags(nameof(Todo)) .WithName("GetAllTodos"); //.Produces>(StatusCodes.Status200OK); group.MapGet("/{id}", async (int id, TodoDbContext db) => { return await db.Todos.FindAsync(id) is Todo model ? Results.Ok(model) : Results.NotFound(); }) .WithTags(nameof(Todo)) .WithName("GetTodoById"); //.Produces(StatusCodes.Status200OK) //.Produces(StatusCodes.Status404NotFound); group.MapPut("/{id}", async (int id, Todo todo, TodoDbContext db) => { var foundModel = await db.Todos.FindAsync(id); if (foundModel is null) { return Results.NotFound(); } db.Update(todo); await db.SaveChangesAsync(); return Results.NoContent(); }) .WithTags(nameof(Todo)) .WithName("UpdateTodo"); //.Produces(StatusCodes.Status404NotFound) //.Produces(StatusCodes.Status204NoContent); group.MapPost("/", async (Todo todo, TodoDbContext db) => { db.Todos.Add(todo); await db.SaveChangesAsync(); return Results.Created($"/api/Todo/{todo.Id}", todo); }) .WithTags(nameof(Todo)) .WithName("CreateTodo"); //.Produces(StatusCodes.Status201Created); group.MapDelete("/{id}", async (int id, TodoDbContext db) => { if (await db.Todos.FindAsync(id) is Todo todo) { db.Todos.Remove(todo); await db.SaveChangesAsync(); return Results.Ok(todo); } return Results.NotFound(); }) .WithTags(nameof(Todo)) .WithName("DeleteTodo"); //.Produces(StatusCodes.Status200OK) // .Produces(StatusCodes.Status404NotFound); } } class Todo { public int Id { get; set; } } class TodoDbContext { public DbSet Todos { get; set; } public Task SaveChangesAsync() => Task.CompletedTask; public void Update(object o) { } } class DbSet { public Task> ToListAsync() { return null; } public Task FindAsync(object id) { return null; } public void Remove(T item) { } public void Add(T item) { } } ================================================ FILE: samples/Program.cs ================================================ using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Primitives; using MinimalApis.Extensions.Binding; using System.Diagnostics.CodeAnalysis; using System.IO.Pipelines; using System.Reflection; using System.Security.Claims; using System.Text.Json.Nodes; var builder = WebApplication.CreateBuilder(); builder.Services.AddSingleton(); var app = builder.Build(); app.MapGet("/", () => "Hello World"); app.MapGet("/hello/{name}", (string name) => $"Hello {name}"); app.MapGet("/anon", () => new { Name = "David" }); app.MapGet("/person", () => new Person("David")); app.MapGet("/ok", (ClaimsPrincipal c, ISayHello hellosvc) => Results.Ok(hellosvc.Hello())); app.MapPost("/implictbody", (JsonNode node) => node).AddEndpointFilter((context, next) => next(context)); app.MapPost("/", ([FromBody] JsonNode node) => node).AddEndpointFilter((context, next) => next(context)); app.MapPost("/model", (Model m) => m); app.MapPost("/model2", (Model m) => { }); app.MapPost("/fileupload", (IFormFile file) => { return $"Uploaded {file.Name}"; }); app.MapGet("/nameofnot", (string name) => name is null ? Results.NotFound() : Results.Ok($"Hello {name}")); app.MapPost("/formpost", (IFormCollection formCollection) => { return $"Uploaded {formCollection.Count} files"; }); app.MapPost("/body", (Body body) => body.Value); app.MapPost("/validated", (Validated model) => { if (!model.IsValid) { return Results.ValidationProblem(model.Errors); } return Results.Ok(); }); app.MapGet("/something", object (CancellationToken ct) => new Person("Hello")); IResult NoAccess(int? id) => Results.StatusCode(401); app.Map("/private", NoAccess); app.MapPost("/post/q", (Stream s) => Results.Stream(s)); app.MapPost("/post/q", (PipeReader r) => Results.Stream(r.AsStream())); app.MapPatch("/patch", (HttpRequest req, HttpResponse resp) => Task.CompletedTask); app.MapGet("/multiple", (StringValues queries) => queries.ToArray()); app.MapGet("/multiple2", (string[] queries) => queries); app.MapGet("/multiple3", (int[] queries) => queries); var api = app.MapGroup("/api"); var personGroup = api.MapGroup("/persons"); personGroup.MapGet("/", () => new Person("David")); api.MapTodoEndpoints(); var s = Wrapper.RoutePattern; app.MapGet(s, new Wrapper().Hello); app.MapGet("/another", Wrapper.HelloDelegate); app.MapGet("/another1", Wrapper.HelloDelegate2); app.MapGet("/choose/{c}", (Choices c) => c.ToString()); var wrapper = new Wrapper(); wrapper.AddRoutes(app); var d = wrapper.Hello; // This can't be resolved // app.MapGet("/del", d); // var path = "/foo/{s}"; var f = (string s) => "hello"; // This neither // app.MapGet(path, f); // void Helper(string s, Func handler) => app.MapGet(s, handler); app.Map("/test/map", (int x) => x); app.Map("/test/map", (int x, int y) => { }); app.MapPut("/test/put", (int x) => x); app.MapPut("/test/put", (int x, int y) => { }); app.MapPost("/test/post", (int x) => x); app.MapPost("/test/post", (int x, int y) => { }); app.MapDelete("/test/delete", (int x) => x); app.MapDelete("/test/delete", (int x, int y) => { }); app.MapPatch("/test/patch", (int x) => x); app.MapPatch("/test/patch", (int x, int y) => { }); app.Map("/test/{n}", (int n) => n); //void Foo([FromBody] JsonNode a1, [FromBody] JsonNode a2) //{ //} //app.MapGet("/twobodies", Foo); const string pattern = "/constpattern/{name}"; app.MapGet(pattern, (string name) => $"Const pattern {name}"); app.MapGet("/something/parsable", ([FromQuery] Parsable p) => p); app.MapGet("/lineinfo", string (HttpContext context) => { var sourceKey = context.GetEndpoint()?.Metadata.GetMetadata(); return sourceKey.ToString(); }); app.Run(); record Person(string Name); record Product(string Name, decimal Price); struct Parsable : IParsable { public Parsable() { } public static Parsable Parse(string s, IFormatProvider provider) { throw new NotImplementedException(); } public static bool TryParse([NotNullWhen(true)] string s, IFormatProvider provider, [MaybeNullWhen(false)] out Parsable result) { throw new NotImplementedException(); } } interface ISayHello { string Hello(); } class EnglishHello : ISayHello { public string Hello() => "Hello"; } public class Model { public static ValueTask BindAsync(HttpContext context, ParameterInfo pi) { return ValueTask.FromResult(new Model()); } } enum Choices { One, Two, Three, } ================================================ FILE: samples/Sample.csproj ================================================  net7.0 preview true enable ================================================ FILE: samples/Wrapper.cs ================================================ class Wrapper { public static readonly string RoutePattern = "/foo/{id}"; public static readonly Func HelloDelegate = Hello2; public static readonly Func HelloDelegate2 = (name) => $"Hello {name}"; public static string Hello2(string name) => $"Hello {name}"; public string Hello(int id) => "Hello World"; public void AddRoutes(IEndpointRouteBuilder routes) { routes.MapGet("/hello2", Hello); } } ================================================ FILE: samples/appsettings.json ================================================ { "Logging": { "LogLevel": { "Default": "Information", "Microsoft": "Warning", "Microsoft.Hosting.Lifetime": "Information" } }, "AllowedHosts": "*" } ================================================ FILE: src/uController.SourceGenerator/AnalyzerReleases.Shipped.md ================================================ ; Shipped analyzer releases ; https://github.com/dotnet/roslyn-analyzers/blob/master/src/Microsoft.CodeAnalysis.Analyzers/ReleaseTrackingAnalyzers.Help.md ================================================ FILE: src/uController.SourceGenerator/AnalyzerReleases.Unshipped.md ================================================ ; Unshipped analyzer release ; https://github.com/dotnet/roslyn-analyzers/blob/master/src/Microsoft.CodeAnalysis.Analyzers/ReleaseTrackingAnalyzers.Help.md ### New Rules Rule ID | Category | Severity | Notes --------|----------|----------|-------------------- MIN001 | Usage | Error | MIN001_uController MIN002 | Usage | Error | MIN002_uController MIN003 | Usage | Error | MIN003_uController MIN005 | Usage | Error | MIN005_uController MIN006 | Usage | Error | MIN006_uController ================================================ FILE: src/uController.SourceGenerator/AwaitableInfo.cs ================================================ // 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.Linq; using System.Reflection; using System.Runtime.CompilerServices; namespace Microsoft.Extensions.Internal { internal readonly struct AwaitableInfo { public Type AwaiterType { get; } public PropertyInfo AwaiterIsCompletedProperty { get; } public MethodInfo AwaiterGetResultMethod { get; } public MethodInfo AwaiterOnCompletedMethod { get; } public MethodInfo AwaiterUnsafeOnCompletedMethod { get; } public Type ResultType { get; } public MethodInfo GetAwaiterMethod { get; } public AwaitableInfo( Type awaiterType, PropertyInfo awaiterIsCompletedProperty, MethodInfo awaiterGetResultMethod, MethodInfo awaiterOnCompletedMethod, MethodInfo awaiterUnsafeOnCompletedMethod, Type resultType, MethodInfo getAwaiterMethod) { AwaiterType = awaiterType; AwaiterIsCompletedProperty = awaiterIsCompletedProperty; AwaiterGetResultMethod = awaiterGetResultMethod; AwaiterOnCompletedMethod = awaiterOnCompletedMethod; AwaiterUnsafeOnCompletedMethod = awaiterUnsafeOnCompletedMethod; ResultType = resultType; GetAwaiterMethod = getAwaiterMethod; } public static bool IsTypeAwaitable(Type type, out AwaitableInfo awaitableInfo) { // Based on Roslyn code: http://source.roslyn.io/#Microsoft.CodeAnalysis.Workspaces/Shared/Extensions/ISymbolExtensions.cs,db4d48ba694b9347 // Awaitable must have method matching "object GetAwaiter()" var getAwaiterMethod = type.GetMethods().FirstOrDefault(m => m.Name.Equals("GetAwaiter", StringComparison.OrdinalIgnoreCase) && m.GetParameters().Length == 0 && m.ReturnType != null); if (getAwaiterMethod == null) { awaitableInfo = default(AwaitableInfo); return false; } var awaiterType = getAwaiterMethod.ReturnType; // Awaiter must have property matching "bool IsCompleted { get; }" var isCompletedProperty = awaiterType.GetProperties().FirstOrDefault(p => p.Name.Equals("IsCompleted", StringComparison.OrdinalIgnoreCase) && p.PropertyType.Equals(typeof(bool)) && p.GetMethod != null); if (isCompletedProperty == null) { awaitableInfo = default(AwaitableInfo); return false; } // Awaiter must implement INotifyCompletion var awaiterInterfaces = awaiterType.GetInterfaces(); var implementsINotifyCompletion = awaiterInterfaces.Any(t => t.Equals(typeof(INotifyCompletion))); if (!implementsINotifyCompletion) { awaitableInfo = default(AwaitableInfo); return false; } // INotifyCompletion supplies a method matching "void OnCompleted(Action action)" //var iNotifyCompletionMap = awaiterType // .GetTypeInfo() // .DeclaredMethods // .GetRuntimeInterfaceMap(getType(typeof(INotifyCompletion))); var onCompletedMethod = awaiterType.GetMethods().Single(m => m.Name.Equals("OnCompleted", StringComparison.OrdinalIgnoreCase) && m.ReturnType.Equals(typeof(void)) && m.GetParameters().Length == 1 && m.GetParameters()[0].ParameterType.Equals(typeof(Action))); // Awaiter optionally implements ICriticalNotifyCompletion var implementsICriticalNotifyCompletion = awaiterInterfaces.Any(t => t.Equals(typeof(ICriticalNotifyCompletion))); MethodInfo unsafeOnCompletedMethod; if (implementsICriticalNotifyCompletion) { // ICriticalNotifyCompletion supplies a method matching "void UnsafeOnCompleted(Action action)" //var iCriticalNotifyCompletionMap = awaiterType // .GetTypeInfo() // .GetRuntimeInterfaceMap(typeof(ICriticalNotifyCompletion)); unsafeOnCompletedMethod = awaiterType.GetMethods().Single(m => m.Name.Equals("UnsafeOnCompleted", StringComparison.OrdinalIgnoreCase) && m.ReturnType.Equals(typeof(void)) && m.GetParameters().Length == 1 && m.GetParameters()[0].ParameterType.Equals(typeof(Action))); } else { unsafeOnCompletedMethod = null; } // Awaiter must have method matching "void GetResult" or "T GetResult()" var getResultMethod = awaiterType.GetMethods().FirstOrDefault(m => m.Name.Equals("GetResult") && m.GetParameters().Length == 0); if (getResultMethod == null) { awaitableInfo = default(AwaitableInfo); return false; } awaitableInfo = new AwaitableInfo( awaiterType, isCompletedProperty, getResultMethod, onCompletedMethod, unsafeOnCompletedMethod, getResultMethod.ReturnType, getAwaiterMethod); return true; } } } ================================================ FILE: src/uController.SourceGenerator/CodeGenerationTypes.cs ================================================ // This class is a helper with the right type names namespace Microsoft.AspNetCore.Http { interface IResult { } class HttpContext { } class HttpRequest { } class HttpResponse { } interface IFormCollection { } interface IFormFile { } class AsParametersAttribute { } class Results { } class TypedResults { } } namespace Microsoft.AspNetCore.Http.Metadata { interface IEndpointMetadataProvider { } interface IEndpointParameterMetadataProvider { } interface IFromServiceMetadata { } interface IFromQueryMetadata { } interface IFromRouteMetadata { } interface IFromBodyMetadata { public bool AllowEmpty { get; } } interface IFromFormMetadata { } interface IFromHeaderMetadata { } } namespace Microsoft.Extensions.Primitives { struct StringValues { } } namespace System.IO.Pipelines { class PipeReader { } } namespace Microsoft.AspNetCore.Routing { interface IEndpointRouteBuilder { } } ================================================ FILE: src/uController.SourceGenerator/HttpModel.cs ================================================ using System; using System.Collections.Generic; using System.Reflection; using Microsoft.CodeAnalysis; using uController.SourceGenerator; namespace uController { class MethodModel { public string UniqueName { get; set; } public MethodInfo MethodInfo { get; set; } public List Parameters { get; } = new List(); public List Metadata { get; } = new List(); public RoutePattern RoutePattern { get; set; } public bool DisableInferBodyFromParameters { get; set; } } class ParameterModel { public MethodModel Method { get; set; } public IParameterSymbol ParameterSymbol { get; set; } public ParameterInfo ParameterInfo { get; set; } public string Name { get; set; } public string GeneratedName { get; set; } public Type ParameterType { get; set; } public string FromQuery { get; set; } public string FromHeader { get; set; } public string FromForm { get; set; } public string FromRoute { get; set; } public CustomAttributeData FromBodyAttributeData { get; set; } public bool FromBody => FromBodyAttributeData != null; public bool FromServices { get; set; } public int Index { get; set; } public bool HasBindingSource => FromBody || FromServices || FromForm != null || FromQuery != null || FromHeader != null || FromRoute != null; public bool Unresovled { get; set; } public bool QueryOrRoute { get; set; } public bool BodyOrService { get; set; } public bool RequiresParameterInfo { get; set; } public bool ReadFromForm { get; set; } } } ================================================ FILE: src/uController.SourceGenerator/MinimalCodeGenerator.cs ================================================ using System; using System.Collections.Generic; using System.IO; using System.IO.Pipelines; using System.Linq; using System.Reflection; using System.Security.Claims; using System.Text; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Microsoft.CodeAnalysis; using Microsoft.Extensions.Internal; using Microsoft.Extensions.Primitives; using Roslyn.Reflection; namespace uController.SourceGenerator { class MinimalCodeGenerator { private readonly StringBuilder _codeBuilder = new(); private readonly WellKnownTypes _wellKnownTypes; private int _indent; public MinimalCodeGenerator(WellKnownTypes wellKnownTypes) { _wellKnownTypes = wellKnownTypes; } public HashSet BodyParameters { get; set; } = new HashSet(); private Type Unwrap(Type type) { if (type.IsGenericType && !type.IsGenericTypeDefinition) { // instantiated generic type only Type genericType = type.GetGenericTypeDefinition(); if (genericType.Equals(typeof(Nullable<>))) { return type.GetGenericArguments()[0]; } } return null; } internal static Type UnwrapValueTask(Type type) { if (type.IsGenericType && !type.IsGenericTypeDefinition) { // instantiated generic type only var genericType = type.GetGenericTypeDefinition(); if (genericType.Equals(typeof(ValueTask<>))) { return type.GetGenericArguments()[0]; } } return null; } public void Indent() { _indent++; } public void Unindent() { _indent--; } public void Generate(MethodModel method) { GenerateMethod(method); WriteLine(""); GenerateFilteredMethod(method); } private void GenerateMethod(MethodModel method) { var methodStartIndex = _codeBuilder.Length + 4 * _indent; WriteLine($"async {typeof(Task)} {method.UniqueName}({typeof(HttpContext)} httpContext)"); WriteLine("{"); Indent(); // Declare locals var hasAwait = false; var hasFromBody = false; var hasFromForm = false; var generatedParamCheck = false; var paramFailureStartIndex = _codeBuilder.Length + 4 * _indent; var paramCheckExpression = "var wasParamCheckFailure = false;"; WriteLine(paramCheckExpression); foreach (var parameter in method.Parameters) { var parameterName = parameter.GeneratedName; EmitParameter(ref hasAwait, ref hasFromBody, ref hasFromForm, ref generatedParamCheck, parameter, parameterName); } var resultExpression = ""; AwaitableInfo awaitableInfo = default; if (method.MethodInfo.ReturnType.Equals(typeof(void))) { resultExpression = ""; } else { if (AwaitableInfo.IsTypeAwaitable(method.MethodInfo.ReturnType, out awaitableInfo)) { if (awaitableInfo.ResultType.Equals(typeof(void))) { if (hasAwait) { resultExpression = "await "; } else { resultExpression = "return "; } } else { resultExpression = "var result = await "; hasAwait = true; } } else { resultExpression = "var result = "; } } if (generatedParamCheck) { WriteLine("if (wasParamCheckFailure)"); WriteLine("{"); Indent(); WriteLine("httpContext.Response.StatusCode = 400;"); if (hasAwait) { WriteLine("return;"); } else { WriteLine("return Task.CompletedTask;"); } Unindent(); WriteLine("}"); } else { var currentIndent = 4 * _indent; _codeBuilder.Remove(paramFailureStartIndex - currentIndent - Environment.NewLine.Length, paramCheckExpression.Length + currentIndent + Environment.NewLine.Length); } Write(resultExpression); WriteNoIndent($"handler("); bool first = true; foreach (var parameter in method.Parameters) { var parameterName = parameter.GeneratedName; if (!first) { WriteNoIndent(", "); } WriteNoIndent(parameterName); first = false; } if (!hasAwait && method.MethodInfo.ReturnType.Equals(typeof(ValueTask))) { // Convert the ValueTask to a Task WriteLineNoIndent(").AsTask();"); } else { WriteLineNoIndent(");"); } if (!hasAwait) { // Remove " async " from method signature. _codeBuilder.Remove(methodStartIndex, 6); } void AwaitOrReturn(string executeAsync) { if (hasAwait) { Write("await "); } else { Write("return "); } WriteLineNoIndent(executeAsync); } var unwrappedType = awaitableInfo.ResultType ?? method.MethodInfo.ReturnType; if (_wellKnownTypes.IResultType.IsAssignableFrom(unwrappedType)) { AwaitOrReturn("result.ExecuteAsync(httpContext);"); } else if (unwrappedType.Equals(typeof(string))) { AwaitOrReturn($"httpContext.Response.WriteAsync(result);"); } else if (unwrappedType.Equals(typeof(object))) { AwaitOrReturn("ExecuteObjectResult(result, httpContext);"); } else if (!unwrappedType.Equals(typeof(void))) { AwaitOrReturn($"httpContext.Response.WriteAsJsonAsync(result);"); } else if (!hasAwait && method.MethodInfo.ReturnType.Equals(typeof(void))) { // If awaitableInfo.ResultType is void, we've already returned the awaitable directly. WriteLine($"return {typeof(Task)}.CompletedTask;"); } Unindent(); WriteLine("}"); } private void GenerateFilteredMethod(MethodModel method) { WriteLine($"async {typeof(Task)} {method.UniqueName}Filtered({typeof(HttpContext)} httpContext)"); WriteLine("{"); Indent(); // Declare locals var hasAwait = false; var hasFromBody = false; var hasFromForm = false; var generatedParamCheck = false; var paramFailureStartIndex = _codeBuilder.Length + 4 * _indent; var paramCheckExpression = "var wasParamCheckFailure = false;"; WriteLine(paramCheckExpression); foreach (var parameter in method.Parameters) { var parameterName = parameter.GeneratedName; EmitParameter(ref hasAwait, ref hasFromBody, ref hasFromForm, ref generatedParamCheck, parameter, parameterName); } if (generatedParamCheck) { WriteLine("if (wasParamCheckFailure)"); WriteLine("{"); Indent(); WriteLine("httpContext.Response.StatusCode = 400;"); Unindent(); WriteLine("}"); } else { var currentIndent = 4 * _indent; _codeBuilder.Remove(paramFailureStartIndex - currentIndent - Environment.NewLine.Length, paramCheckExpression.Length + currentIndent + Environment.NewLine.Length); } Write("var result = await "); WriteNoIndent($"filteredInvocation(new DefaultEndpointFilterInvocationContext(httpContext"); foreach (var parameter in method.Parameters) { WriteNoIndent(", "); WriteNoIndent(parameter.GeneratedName); } WriteLineNoIndent("));"); void AwaitOrReturn(string executeAsync) { Write("await "); WriteLineNoIndent(executeAsync); } AwaitOrReturn("ExecuteObjectResult(result, httpContext);"); Unindent(); WriteLine("}"); } private void EmitParameter(ref bool hasAwait, ref bool hasFromBody, ref bool hasForm, ref bool generatedParamCheck, ParameterModel parameter, string parameterName) { var defaultValue = parameter.ParameterSymbol.HasExplicitDefaultValue ? parameter.ParameterSymbol.ExplicitDefaultValue : null; var isOptional = parameter.ParameterSymbol.IsOptional || parameter.ParameterSymbol.NullableAnnotation == NullableAnnotation.Annotated; if (parameter.ParameterType.Equals(typeof(HttpContext))) { WriteLine($"var {parameterName} = httpContext;"); } else if (parameter.ParameterType.Equals(typeof(HttpRequest))) { WriteLine($"var {parameterName} = httpContext.Request;"); } else if (parameter.ParameterType.Equals(typeof(HttpResponse))) { WriteLine($"var {parameterName} = httpContext.Response;"); } else if (parameter.ParameterType.Equals(typeof(IFormFile))) { if (!hasForm) { WriteLine($"var formCollection = await httpContext.Request.ReadFormAsync();"); hasAwait = true; hasForm = true; } WriteLine($@"var {parameterName} = formCollection.Files[""{parameter.Name}""];"); parameter.ReadFromForm = true; } else if (parameter.ParameterType.Equals(typeof(IFormCollection))) { if (!hasForm) { WriteLine($"var formCollection = await httpContext.Request.ReadFormAsync();"); hasAwait = true; hasForm = true; } WriteLine($"var {parameterName} = formCollection;"); parameter.ReadFromForm = true; } else if (parameter.ParameterType.Equals(typeof(ClaimsPrincipal))) { WriteLine($"var {parameterName} = httpContext.User;"); } else if (parameter.ParameterType.Equals(typeof(CancellationToken))) { WriteLine($"var {parameterName} = httpContext.RequestAborted;"); } else if (parameter.ParameterType.Equals(typeof(Stream))) { WriteLine($"var {parameterName} = httpContext.Request.Body;"); } else if (parameter.ParameterType.Equals(typeof(PipeReader))) { WriteLine($"var {parameterName} = httpContext.Request.BodyReader;"); } else if (parameter.FromRoute != null) { if (!GenerateConvert(parameterName, parameter.ParameterInfo, parameter.ParameterType, defaultValue, parameter.FromRoute, "httpContext.Request.RouteValues", ref generatedParamCheck, nullable: true)) { parameter.Unresovled = true; } } else if (parameter.FromQuery != null) { if (!GenerateConvert(parameterName, parameter.ParameterInfo, parameter.ParameterType, defaultValue, parameter.FromQuery, "httpContext.Request.Query", ref generatedParamCheck, sourcedFromStringValue: true)) { parameter.Unresovled = true; } } else if (parameter.FromHeader != null) { if (!GenerateConvert(parameterName, parameter.ParameterInfo, parameter.ParameterType, defaultValue, parameter.FromHeader, "httpContext.Request.Headers", ref generatedParamCheck, sourcedFromStringValue: true)) { parameter.Unresovled = true; } } else if (parameter.FromServices) { if (isOptional) { WriteLine($"var {parameterName} = httpContext.RequestServices.GetService<{parameter.ParameterType}>();"); } else { WriteLine($"var {parameterName} = httpContext.RequestServices.GetRequiredService<{parameter.ParameterType}>();"); } } else if (parameter.FromForm != null) { if (!hasForm) { WriteLine($"var formCollection = await httpContext.Request.ReadFormAsync();"); hasAwait = true; hasForm = true; } if (!GenerateConvert(parameterName, parameter.ParameterInfo, parameter.ParameterType, defaultValue, parameter.FromForm, "formCollection", ref generatedParamCheck)) { parameter.Unresovled = true; } parameter.ReadFromForm = true; } else if (parameter.FromBody) { BodyParameters.Add(parameter); var allowEmptyKey = "AllowEmpty"; // Check existence of argument beforehand to avoid null-ref if (parameter.FromBodyAttributeData is {} fromBodyAttribute && fromBodyAttribute.NamedArguments.Any(n => n.MemberName == allowEmptyKey)) { var allowEmpty = fromBodyAttribute?.GetNamedArgument(allowEmptyKey) ?? false; isOptional |= allowEmpty; } if (parameter.ParameterType.Equals(typeof(PipeReader))) { WriteLine($"var {parameterName} = httpContext.Request.BodyReader;"); } else if (parameter.ParameterType.Equals(typeof(Stream))) { WriteLine($"var {parameterName} = httpContext.Request.Body;"); } else { WriteLine($"var {parameterName} = await ResolveBody<{parameter.ParameterType}>(httpContext, {(isOptional ? "true" : "false")});"); } hasAwait = true; } else { // Error if we can't determine the binding source for this parameter var parameterType = Unwrap(parameter.ParameterType) ?? parameter.ParameterType; if (HasBindAsync(parameterType, out var bindAsyncMethod, out var parameterCount, out var returnType)) { if (parameterCount == 1) { WriteLine($"var {parameterName}Nullable = await {bindAsyncMethod.DeclaringType}.BindAsync(httpContext);"); } else { parameter.RequiresParameterInfo = true; WriteLine($"var {parameterName}Nullable = await {bindAsyncMethod.DeclaringType}.BindAsync(httpContext, {parameter.GeneratedName}ParameterInfo);"); } var generatedBindAsyncAssignment = false; // Emit null check when the parameter is required // but the `BindAsync` can resolve to a nullable value if (UnwrapValueTask(returnType) is RoslynType innerReturn // Gets the T in ValueTask && parameter.ParameterSymbol.NullableAnnotation != NullableAnnotation.Annotated && innerReturn.TypeSymbol.NullableAnnotation == NullableAnnotation.Annotated) // Gets the T in T? { WriteLine($"if ({parameterName}Nullable == null)"); WriteLine("{"); Indent(); WriteLine("httpContext.Response.StatusCode = 400;"); WriteLine("return;"); Unindent(); WriteLine("}"); // If the result of `BindAsync` is nullable and the parameter // is not a value type then emit the value of the resolved // nullable value if (innerReturn.TypeSymbol.IsValueType) { WriteLine($"var {parameterName} = {parameterName}Nullable.Value;"); generatedBindAsyncAssignment = true; } } // Get the default out of the parameter if (!generatedBindAsyncAssignment) { WriteLine($"var {parameterName} = {parameterName}Nullable;"); } hasAwait = true; } else if (HasTryParseMethod(parameterType, out var tryParseMethod) || parameterType.Equals(typeof(string)) || parameterType.Equals(typeof(StringValues)) || parameterType.Equals(typeof(string[])) || parameterType.IsArray && HasTryParseMethod(parameterType.GetElementType(), out tryParseMethod)) { parameter.QueryOrRoute = true; // Fallback to resolver if (!GenerateConvert(parameterName, parameter.ParameterInfo, parameter.ParameterType, defaultValue, parameter.Name, $"{parameter.GeneratedName}RouteOrQueryResolver", ref generatedParamCheck, methodCall: true, tryParseMethod: tryParseMethod, sourcedFromStringValue: true)) { parameter.Unresovled = true; } } else { parameter.BodyOrService = true; hasAwait = true; WriteLine($"var {parameterName} = await {parameterName}ServiceOrBodyResolver(httpContext);"); } } } private bool HasTryParseMethod(Type type, out MethodInfo mi) { // TODO: Handle specific types (Uri, DateTime etc) with relevant options mi = null; if (type.IsEnum) { // Use Enum.TryParse(string, bool, out T) for enums mi = GetEnumTryParseMethod(); } mi ??= GetStaticMethodFromHierarchy(type, "TryParse", new[] { typeof(string), type.MakeByRefType() }, m => m.ReturnType.Equals(typeof(bool))); mi ??= GetStaticMethodFromHierarchy(type, "TryParse", new[] { typeof(string), _wellKnownTypes.IFormatProviderType, type.MakeByRefType() }, m => m.ReturnType.Equals(typeof(bool))); return mi != null; } private bool HasBindAsync(Type type, out MethodInfo mi, out int parameterCount, out Type returnType) { mi = GetStaticMethodFromHierarchy(type, "BindAsync", new[] { _wellKnownTypes.HttpContextType }, m => true); mi ??= GetStaticMethodFromHierarchy(type, "BindAsync", new[] { _wellKnownTypes.HttpContextType, _wellKnownTypes.ParamterInfoType }, m => true); parameterCount = mi?.GetParameters().Length ?? 0; returnType = mi?.ReturnType; return mi != null; } private bool GenerateConvert(string sourceName, ParameterInfo parameterInfo, Type type, object defaultValue, string key, string sourceExpression, ref bool generatedParamCheck, bool nullable = false, bool methodCall = false, MethodInfo tryParseMethod = null, bool sourcedFromStringValue = false) { var getter = methodCall ? $@"{sourceExpression}(httpContext, ""{key}"")" : $@"{sourceExpression}[""{key}""]"; WriteLine($"var getter{sourceName}Value = {getter};"); if (!(parameterInfo as RoslynParameterInfo).IsOptional) { generatedParamCheck = true; if (sourcedFromStringValue) { WriteLine($"if (string.IsNullOrEmpty(getter{sourceName}Value))"); } else { WriteLine($"if (getter{sourceName}Value == null)"); } WriteLine("{"); Indent(); WriteLine("wasParamCheckFailure = true;"); Unindent(); WriteLine("}"); } if (type.Equals(typeof(string))) { if (defaultValue is null) { WriteLine($"var {sourceName} = getter{sourceName}Value" + (nullable ? "?.ToString();" : ".ToString();")); } else { if (nullable) { WriteLine($@"var {sourceName} = getter{sourceName}Value?.ToString() ?? ""{defaultValue}"";"); } else { WriteLine($@"var {sourceName}Str = getter{sourceName}Value.ToString();"); WriteLine($@"var {sourceName} = string.IsNullOrEmpty({sourceName}Str) ? ""{defaultValue}"" : {sourceName}Str;"); } } } else if (type.Equals(typeof(StringValues))) { WriteLine($"var {sourceName} = getter{sourceName}Value.Value;"); } else if (type.Equals(typeof(StringValues?))) { WriteLine($"var {sourceName} = getter{sourceName}Value;"); } else if (type.Equals(typeof(string[]))) { WriteLine($"var {sourceName} = getter{sourceName}Value?.ToArray();"); } else { var unwrappedType = Unwrap(type) ?? type; if (tryParseMethod is null) { if (!HasTryParseMethod(unwrappedType, out tryParseMethod)) { WriteLine($"{type} {sourceName} = default;"); return false; } } if (type.IsArray) { var elementType = type.GetElementType(); WriteLine($"var {sourceName}_Value = getter{sourceName}Value?.ToArray();"); WriteLine($"{elementType}[] {sourceName} = default;"); WriteLine($"for (var i = 0; i < {sourceName}.Length; i++)"); WriteLine("{"); Indent(); WriteLine($"{sourceName} ??= new {elementType}[{sourceName}_Value.Length];"); GenerateTryParse(tryParseMethod, $"{sourceName}_Value[i]", $"{sourceName}[i]", elementType, null, ref generatedParamCheck); Unindent(); WriteLine("}"); // TODO: Nullability WriteLine($"{sourceName} ??= System.Array.Empty<{elementType}>();"); } else { WriteLine($"var {sourceName}_Value = getter{sourceName}Value" + (nullable ? "?.ToString();" : ".ToString();")); WriteLine($"{type} {sourceName};"); GenerateTryParse(tryParseMethod, $"{sourceName}_Value", sourceName, type, defaultValue, ref generatedParamCheck); } } return true; } private void GenerateTryParse(MethodInfo tryParseMethod, string sourceName, string outputName, Type type, object defaultValue, ref bool generatedParamCheck) { var underlyingType = Unwrap(type); // Support different TryParse overloads string TryParseExpression(string outputExpression) => (tryParseMethod.DeclaringType, tryParseMethod.GetParameters().Length) switch { (_, 2) => $"{tryParseMethod.DeclaringType}.TryParse({sourceName}, out {outputExpression})", (var type, 3) when type.Equals(_wellKnownTypes.EnumType) => $"{tryParseMethod.DeclaringType}.TryParse({sourceName}, true, out {outputExpression})", (_, 3) => $"{tryParseMethod.DeclaringType}.TryParse({sourceName}, System.Globalization.CultureInfo.InvariantCulture, out {outputExpression})", _ => throw new NotSupportedException("Unknown TryParse method") }; // Type isn't nullable if (underlyingType is null) { generatedParamCheck = true; // No source, no default value // No source but has a default value // Unable to parse if (defaultValue is null) { WriteLine($"if ({sourceName} == null || !{TryParseExpression(outputName)})"); WriteLine("{"); Indent(); WriteLine($"{outputName} = default;"); WriteLine("wasParamCheckFailure = true;"); Unindent(); WriteLine("}"); } else { WriteLine($"if (string.IsNullOrEmpty({sourceName}))"); WriteLine("{"); Indent(); WriteLine($"{outputName} = {defaultValue};"); Unindent(); WriteLine("}"); WriteLine($"else if (!{TryParseExpression(outputName)})"); WriteLine("{"); Indent(); WriteLine($"{outputName} = default;"); WriteLine("wasParamCheckFailure = true;"); Unindent(); WriteLine("}"); } } else { WriteLine($"if ({sourceName} != null && {TryParseExpression($"var {outputName}_Temp")})"); WriteLine("{"); Indent(); WriteLine($"{outputName} = {outputName}_Temp;"); Unindent(); WriteLine("}"); WriteLine("else"); WriteLine("{"); Indent(); if (defaultValue is null) { WriteLine($"{outputName} = default;"); } else { WriteLine($"{outputName} = {defaultValue};"); } Unindent(); WriteLine("}"); } } private MethodInfo GetEnumTryParseMethod() { var tryParse = (from m in _wellKnownTypes.EnumType.GetMethods(BindingFlags.Public | BindingFlags.Static) let parameters = m.GetParameters() where parameters.Length == 3 && m.Name == "TryParse" && m.IsGenericMethod && parameters[0].ParameterType.Equals(typeof(string)) && parameters[1].ParameterType.Equals(typeof(bool)) select m).FirstOrDefault(); return tryParse; } private MethodInfo GetStaticMethodFromHierarchy(Type type, string name, Type[] parameterTypes, Func validateReturnType) { bool IsMatch(MethodInfo method) => method is not null && !method.IsAbstract && validateReturnType(method); var methodInfo = type.GetMethod(name, BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy, binder: null, types: parameterTypes, modifiers: default); if (IsMatch(methodInfo)) { return methodInfo; } var candidateInterfaceMethodInfo = default(MethodInfo); // Check all interfaces for implementations. Fail if there are duplicates. foreach (var implementedInterface in type.GetInterfaces()) { var interfaceMethod = implementedInterface.GetMethod(name, BindingFlags.Public | BindingFlags.Static, binder: null, types: parameterTypes, modifiers: default); if (IsMatch(interfaceMethod)) { if (candidateInterfaceMethodInfo is not null) { return null; } candidateInterfaceMethodInfo = interfaceMethod; } } return candidateInterfaceMethodInfo; } private void WriteLineNoIndent(string value) { _codeBuilder.AppendLine(value); } private void WriteNoIndent(string value) { _codeBuilder.Append(value); } private void Write(string value) { if (_indent > 0) { _codeBuilder.Append(new string(' ', _indent * 4)); } _codeBuilder.Append(value); } private void WriteLine(string value) { if (_indent > 0) { _codeBuilder.Append(new string(' ', _indent * 4)); } _codeBuilder.AppendLine(value); } public override string ToString() { return _codeBuilder.ToString(); } } } ================================================ FILE: src/uController.SourceGenerator/Reflection/MetadataLoadContext.cs ================================================ using System; using System.Collections.Concurrent; using System.Linq; using System.Reflection; using Microsoft.CodeAnalysis; #nullable disable namespace Roslyn.Reflection { public class MetadataLoadContext { private readonly Compilation _compilation; private readonly ConcurrentDictionary _cache = new(SymbolEqualityComparer.IncludeNullability); public MetadataLoadContext(Compilation compilation) { _compilation = compilation; } public Assembly Assembly => _compilation.Assembly.AsAssembly(this); internal Compilation Compilation => _compilation; public Type ResolveType(string fullyQualifiedMetadataName) { return _compilation.GetTypeByMetadataName(fullyQualifiedMetadataName)?.AsType(this); } public Type ResolveType() => ResolveType(typeof(T)); public Type ResolveType(Type type) { if (type is RoslynType) { return type; } var resolvedType = _compilation.GetTypeByMetadataName(type.FullName); if (resolvedType is not null) { return resolvedType.AsType(this); } if (type.IsArray) { var typeSymbol = _compilation.GetTypeByMetadataName(type.GetElementType().FullName); if (typeSymbol is null) { return null; } return _compilation.CreateArrayTypeSymbol(typeSymbol).AsType(this); } if (type.IsGenericType) { var openGenericTypeSymbol = _compilation.GetTypeByMetadataName(type.GetGenericTypeDefinition().FullName); if (openGenericTypeSymbol is null) { return null; } return openGenericTypeSymbol.AsType(this).MakeGenericType(type.GetGenericArguments()); } return null; } public TMember GetOrCreate(ISymbol symbol) where TMember : class { if (symbol is null) { return null; } return (TMember)_cache.GetOrAdd(symbol, s => s switch { ITypeSymbol t => new RoslynType(t, this), IFieldSymbol f => new RoslynFieldInfo(f, this), IPropertySymbol p => new RoslynPropertyInfo(p, this), IMethodSymbol c when c.MethodKind == MethodKind.Constructor => new RoslynConstructorInfo(c, this), IMethodSymbol m => new RoslynMethodInfo(m, this), IParameterSymbol param => new RoslynParameterInfo(param, this), IAssemblySymbol a => new RoslynAssembly(a, this), _ => null }); } public TMember ResolveMember(TMember memberInfo) where TMember : MemberInfo { return memberInfo switch { RoslynFieldInfo f => (TMember)(object)f, RoslynMethodInfo m => (TMember)(object)m, RoslynPropertyInfo p => (TMember)(object)p, MethodInfo m => (TMember)(object)ResolveType(m.ReflectedType)?.GetMethod(m.Name, SharedUtilities.ComputeBindingFlags(m), binder: null, types: m.GetParameters().Select(t => t.ParameterType).ToArray(), modifiers: null), PropertyInfo p => (TMember)(object)ResolveType(p.ReflectedType)?.GetProperty(p.Name, SharedUtilities.ComputeBindingFlags(p), binder: null, returnType: p.PropertyType, types: p.GetIndexParameters().Select(t => t.ParameterType).ToArray(), modifiers: null), FieldInfo f => (TMember)(object)ResolveType(f.ReflectedType)?.GetField(f.Name, SharedUtilities.ComputeBindingFlags(f)), _ => null }; } } } #nullable restore ================================================ FILE: src/uController.SourceGenerator/Reflection/RoslynAssembly.cs ================================================ using System; using System.Collections.Generic; using System.Reflection; using Microsoft.CodeAnalysis; #nullable disable namespace Roslyn.Reflection { internal class RoslynAssembly : Assembly { private readonly MetadataLoadContext _metadataLoadContext; public RoslynAssembly(IAssemblySymbol assembly, MetadataLoadContext metadataLoadContext) { Symbol = assembly; _metadataLoadContext = metadataLoadContext; } public override string FullName => Symbol.Name; internal IAssemblySymbol Symbol { get; } public override Type[] GetExportedTypes() { return GetTypes(); } public override Type[] GetTypes() { var types = new List(); var stack = new Stack(); stack.Push(Symbol.GlobalNamespace); while (stack.Count > 0) { var current = stack.Pop(); foreach (var type in current.GetTypeMembers()) { types.Add(type.AsType(_metadataLoadContext)); } foreach (var ns in current.GetNamespaceMembers()) { stack.Push(ns); } } return types.ToArray(); } public override Type GetType(string name) { return Symbol.GetTypeByMetadataName(name).AsType(_metadataLoadContext); } } } #nullable restore ================================================ FILE: src/uController.SourceGenerator/Reflection/RoslynConstructorInfo.cs ================================================ using System; using System.Collections.Generic; using System.Globalization; using System.Reflection; using Microsoft.CodeAnalysis; #nullable disable namespace Roslyn.Reflection { internal class RoslynConstructorInfo : ConstructorInfo { private readonly IMethodSymbol _ctor; private readonly MetadataLoadContext _metadataLoadContext; public RoslynConstructorInfo(IMethodSymbol ctor, MetadataLoadContext metadataLoadContext) { _ctor = ctor; _metadataLoadContext = metadataLoadContext; Attributes = SharedUtilities.GetMethodAttributes(ctor); } public override Type DeclaringType => _ctor.ContainingType.AsType(_metadataLoadContext); public override MethodAttributes Attributes { get; } public override RuntimeMethodHandle MethodHandle => throw new NotSupportedException(); public override string Name => _ctor.Name; public override Type ReflectedType => throw new NotImplementedException(); public override bool IsGenericMethod => _ctor.IsGenericMethod; public override Type[] GetGenericArguments() { var typeArguments = new List(); foreach (var t in _ctor.TypeArguments) { typeArguments.Add(t.AsType(_metadataLoadContext)); } return typeArguments.ToArray(); } public override IList GetCustomAttributesData() { return SharedUtilities.GetCustomAttributesData(_ctor, _metadataLoadContext); } public override object[] GetCustomAttributes(bool inherit) { throw new NotSupportedException(); } public override object[] GetCustomAttributes(Type attributeType, bool inherit) { throw new NotSupportedException(); } public override MethodImplAttributes GetMethodImplementationFlags() { throw new NotImplementedException(); } public override ParameterInfo[] GetParameters() { List parameters = default; foreach (var p in _ctor.Parameters) { parameters ??= new(); parameters.Add(p.AsParameterInfo(_metadataLoadContext)); } return parameters?.ToArray() ?? Array.Empty(); } public override object Invoke(BindingFlags invokeAttr, Binder binder, object[] parameters, CultureInfo culture) { throw new NotSupportedException(); } public override object Invoke(object obj, BindingFlags invokeAttr, Binder binder, object[] parameters, CultureInfo culture) { throw new NotSupportedException(); } public override bool IsDefined(Type attributeType, bool inherit) { throw new NotImplementedException(); } } } #nullable restore ================================================ FILE: src/uController.SourceGenerator/Reflection/RoslynCustomAttributeData.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using Microsoft.CodeAnalysis; #nullable disable namespace Roslyn.Reflection { internal class RoslynCustomAttributeData : CustomAttributeData { public RoslynCustomAttributeData(AttributeData a, MetadataLoadContext metadataLoadContext) { if (a.AttributeConstructor is null) { throw new InvalidOperationException(); } var namedArguments = new List(); foreach (var na in a.NamedArguments) { var member = a.AttributeClass.BaseTypes().SelectMany(t => t.GetMembers(na.Key)).First(); MemberInfo memberInfo = member switch { IPropertySymbol property => property.AsPropertyInfo(metadataLoadContext), IFieldSymbol field => field.AsFieldInfo(metadataLoadContext), IMethodSymbol ctor when ctor.MethodKind == MethodKind.Constructor => ctor.AsConstructorInfo(metadataLoadContext), IMethodSymbol method => method.AsMethodInfo(metadataLoadContext), ITypeSymbol typeSymbol => typeSymbol.AsType(metadataLoadContext), _ => null, }; if (memberInfo is not null) { namedArguments.Add(new CustomAttributeNamedArgument(memberInfo, na.Value.Value)); } } var constructorArguments = new List(); foreach (var ca in a.ConstructorArguments) { if (ca.Kind == TypedConstantKind.Error) { continue; } object value = ca.Kind == TypedConstantKind.Array ? ca.Values : ca.Value; constructorArguments.Add(new CustomAttributeTypedArgument(ca.Type.AsType(metadataLoadContext), value)); } Constructor = a.AttributeConstructor.AsConstructorInfo(metadataLoadContext); NamedArguments = namedArguments; ConstructorArguments = constructorArguments; } public override ConstructorInfo Constructor { get; } public override IList NamedArguments { get; } public override IList ConstructorArguments { get; } } } #nullable restore ================================================ FILE: src/uController.SourceGenerator/Reflection/RoslynExtensions.cs ================================================ using System; using System.Collections.Generic; using System.Reflection; using Microsoft.CodeAnalysis; #nullable disable namespace Roslyn.Reflection { public static class RoslynExtensions { public static IMethodSymbol GetMethodSymbol(this MethodInfo methodInfo) => (methodInfo as RoslynMethodInfo)?.MethodSymbol; public static IPropertySymbol GetPropertySymbol(this PropertyInfo property) => (property as RoslynPropertyInfo)?.PropertySymbol; public static IFieldSymbol GetFieldSymbol(this FieldInfo field) => (field as RoslynFieldInfo)?.FieldSymbol; public static IParameterSymbol GetParameterSymbol(this ParameterInfo parameterInfo) => (parameterInfo as RoslynParameterInfo)?.ParameterSymbol; public static ITypeSymbol GetTypeSymbol(this Type type) => (type as RoslynType)?.TypeSymbol; } internal static class RoslynInternalExtensions { public static Assembly AsAssembly(this IAssemblySymbol assemblySymbol, MetadataLoadContext metadataLoadContext) => metadataLoadContext.GetOrCreate(assemblySymbol); public static Type AsType(this ITypeSymbol typeSymbol, MetadataLoadContext metadataLoadContext) => metadataLoadContext.GetOrCreate(typeSymbol); public static ParameterInfo AsParameterInfo(this IParameterSymbol parameterSymbol, MetadataLoadContext metadataLoadContext) => metadataLoadContext.GetOrCreate(parameterSymbol); public static ConstructorInfo AsConstructorInfo(this IMethodSymbol methodSymbol, MetadataLoadContext metadataLoadContext) => metadataLoadContext.GetOrCreate(methodSymbol); public static MethodInfo AsMethodInfo(this IMethodSymbol methodSymbol, MetadataLoadContext metadataLoadContext) => metadataLoadContext.GetOrCreate(methodSymbol); public static PropertyInfo AsPropertyInfo(this IPropertySymbol propertySymbol, MetadataLoadContext metadataLoadContext) => metadataLoadContext.GetOrCreate(propertySymbol); public static FieldInfo AsFieldInfo(this IFieldSymbol fieldSymbol, MetadataLoadContext metadataLoadContext) => metadataLoadContext.GetOrCreate(fieldSymbol); public static IEnumerable BaseTypes(this ITypeSymbol typeSymbol) { var t = typeSymbol; while (t != null) { yield return t; t = t.BaseType; } } } } #nullable restore ================================================ FILE: src/uController.SourceGenerator/Reflection/RoslynFieldInfo.cs ================================================ using System; using System.Collections.Generic; using System.Globalization; using System.Reflection; using Microsoft.CodeAnalysis; #nullable disable namespace Roslyn.Reflection { internal class RoslynFieldInfo : FieldInfo { private readonly IFieldSymbol _field; private readonly MetadataLoadContext _metadataLoadContext; private FieldAttributes? _attributes; public RoslynFieldInfo(IFieldSymbol parameter, MetadataLoadContext metadataLoadContext) { _field = parameter; _metadataLoadContext = metadataLoadContext; } public IFieldSymbol FieldSymbol => _field; public override FieldAttributes Attributes { get { if (!_attributes.HasValue) { _attributes = default(FieldAttributes); if (_field.IsStatic) { _attributes |= FieldAttributes.Static; } if (_field.IsReadOnly) { _attributes |= FieldAttributes.InitOnly; } switch (_field.DeclaredAccessibility) { case Accessibility.Public: _attributes |= FieldAttributes.Public; break; case Accessibility.Private: _attributes |= FieldAttributes.Private; break; case Accessibility.Protected: _attributes |= FieldAttributes.Family; break; } } return _attributes.Value; } } public override RuntimeFieldHandle FieldHandle => throw new NotSupportedException(); public override Type FieldType => _field.Type.AsType(_metadataLoadContext); public override Type DeclaringType => _field.ContainingType.AsType(_metadataLoadContext); public override string Name => _field.Name; public override Type ReflectedType => throw new NotImplementedException(); public override object[] GetCustomAttributes(bool inherit) { throw new NotSupportedException(); } public override object[] GetCustomAttributes(Type attributeType, bool inherit) { throw new NotSupportedException(); } public override object GetValue(object obj) { throw new NotSupportedException(); } public override IList GetCustomAttributesData() { return SharedUtilities.GetCustomAttributesData(_field, _metadataLoadContext); } public override bool IsDefined(Type attributeType, bool inherit) { throw new NotSupportedException(); } public override void SetValue(object obj, object value, BindingFlags invokeAttr, Binder binder, CultureInfo culture) { throw new NotSupportedException(); } public override string ToString() => _field.ToString(); } } #nullable restore ================================================ FILE: src/uController.SourceGenerator/Reflection/RoslynMemberInfo.cs ================================================ using System; using System.Collections.Generic; using System.Reflection; using Microsoft.CodeAnalysis; namespace Roslyn.Reflection { internal class RoslynMemberInfo : MemberInfo { private readonly ISymbol _member; private readonly MetadataLoadContext _metadataLoadContext; public RoslynMemberInfo(ISymbol member, MetadataLoadContext metadataLoadContext) { _member = member; _metadataLoadContext = metadataLoadContext; } public override Type DeclaringType => _member.ContainingType.AsType(_metadataLoadContext); public override MemberTypes MemberType => throw new NotImplementedException(); public override string Name => _member.Name; public override Type ReflectedType => throw new NotImplementedException(); public override IList GetCustomAttributesData() { return SharedUtilities.GetCustomAttributesData(_member, _metadataLoadContext); } public override object[] GetCustomAttributes(bool inherit) { throw new NotSupportedException(); } public override object[] GetCustomAttributes(Type attributeType, bool inherit) { throw new NotSupportedException(); } public override bool IsDefined(Type attributeType, bool inherit) { throw new NotSupportedException(); } } } ================================================ FILE: src/uController.SourceGenerator/Reflection/RoslynMethodInfo.cs ================================================ using System; using System.Collections.Generic; using System.Data; using System.Globalization; using System.Reflection; using Microsoft.CodeAnalysis; #nullable disable namespace Roslyn.Reflection { internal class RoslynMethodInfo : MethodInfo { private readonly IMethodSymbol _method; private readonly MetadataLoadContext _metadataLoadContext; public RoslynMethodInfo(IMethodSymbol method, MetadataLoadContext metadataLoadContext) { _method = method; _metadataLoadContext = metadataLoadContext; Attributes = SharedUtilities.GetMethodAttributes(method); } public override ICustomAttributeProvider ReturnTypeCustomAttributes => throw new NotImplementedException(); public override MethodAttributes Attributes { get; } public override RuntimeMethodHandle MethodHandle => throw new NotSupportedException(); public override Type DeclaringType => _method.ContainingType.AsType(_metadataLoadContext); public override Type ReturnType => _method.ReturnType.AsType(_metadataLoadContext); public override string Name => _method.Name; public override bool IsGenericMethod => _method.IsGenericMethod; public override Type ReflectedType => throw new NotImplementedException(); public IMethodSymbol MethodSymbol => _method; public override IList GetCustomAttributesData() { return SharedUtilities.GetCustomAttributesData(_method, _metadataLoadContext); } public override MethodInfo GetBaseDefinition() { var method = _method; // Walk until we find the base definition for this method while (method.OverriddenMethod is not null) { method = method.OverriddenMethod; } if (method.Equals(_method, SymbolEqualityComparer.Default)) { return this; } return method.AsMethodInfo(_metadataLoadContext); } public override MethodInfo MakeGenericMethod(params Type[] typeArguments) { var typeSymbols = new ITypeSymbol[typeArguments.Length]; for (int i = 0; i < typeSymbols.Length; i++) { typeSymbols[i] = _metadataLoadContext.ResolveType(typeArguments[i]).GetTypeSymbol(); } return _method.Construct(typeSymbols).AsMethodInfo(_metadataLoadContext); } public override object[] GetCustomAttributes(bool inherit) { throw new NotSupportedException(); } public override object[] GetCustomAttributes(Type attributeType, bool inherit) { throw new NotSupportedException(); } public override Type[] GetGenericArguments() { List typeArguments = default; foreach (var t in _method.TypeArguments) { typeArguments ??= new(); typeArguments.Add(t.AsType(_metadataLoadContext)); } return typeArguments?.ToArray() ?? Array.Empty(); } public override MethodImplAttributes GetMethodImplementationFlags() { throw new NotImplementedException(); } public override ParameterInfo[] GetParameters() { List parameters = default; foreach (var p in _method.Parameters) { parameters ??= new(); parameters.Add(p.AsParameterInfo(_metadataLoadContext)); } return parameters?.ToArray() ?? Array.Empty(); } public override object Invoke(object obj, BindingFlags invokeAttr, Binder binder, object[] parameters, CultureInfo culture) { throw new NotSupportedException(); } public override bool IsDefined(Type attributeType, bool inherit) { throw new NotSupportedException(); } public override string ToString() => _method.ToString(); } } #nullable restore ================================================ FILE: src/uController.SourceGenerator/Reflection/RoslynParameterInfo.cs ================================================ using System; using System.Collections.Generic; using System.Reflection; using Microsoft.CodeAnalysis; #nullable disable namespace Roslyn.Reflection { public class RoslynParameterInfo : ParameterInfo { private readonly IParameterSymbol _parameter; private readonly MetadataLoadContext _metadataLoadContext; public RoslynParameterInfo(IParameterSymbol parameter, MetadataLoadContext metadataLoadContext) { _parameter = parameter; _metadataLoadContext = metadataLoadContext; } public IParameterSymbol ParameterSymbol => _parameter; public override Type ParameterType => _parameter.Type.AsType(_metadataLoadContext); public override string Name => _parameter.Name; public override bool HasDefaultValue => _parameter.HasExplicitDefaultValue; public override object DefaultValue => HasDefaultValue ? _parameter.ExplicitDefaultValue : null; public new bool IsOptional => HasDefaultValue || _parameter.NullableAnnotation == NullableAnnotation.Annotated; public override int Position => _parameter.Ordinal; public override IList GetCustomAttributesData() { return SharedUtilities.GetCustomAttributesData(_parameter, _metadataLoadContext); } public override string ToString() => _parameter.ToString(); } } #nullable restore ================================================ FILE: src/uController.SourceGenerator/Reflection/RoslynPropertyInfo.cs ================================================ using System; using System.Collections.Generic; using System.Globalization; using System.Reflection; using Microsoft.CodeAnalysis; #nullable disable namespace Roslyn.Reflection { internal class RoslynPropertyInfo : PropertyInfo { private readonly IPropertySymbol _property; private readonly MetadataLoadContext _metadataLoadContext; public RoslynPropertyInfo(IPropertySymbol property, MetadataLoadContext metadataLoadContext) { _property = property; _metadataLoadContext = metadataLoadContext; } public IPropertySymbol PropertySymbol => _property; public override PropertyAttributes Attributes => throw new NotImplementedException(); public override bool CanRead => _property.GetMethod != null; public override bool CanWrite => _property.SetMethod != null; public override Type PropertyType => _property.Type.AsType(_metadataLoadContext); public override Type DeclaringType => _property.ContainingType.AsType(_metadataLoadContext); public override string Name => _property.Name; public override Type ReflectedType => throw new NotImplementedException(); public override MethodInfo[] GetAccessors(bool nonPublic) { throw new NotImplementedException(); } public override object[] GetCustomAttributes(bool inherit) { throw new NotSupportedException(); } public override object[] GetCustomAttributes(Type attributeType, bool inherit) { throw new NotSupportedException(); } public override MethodInfo GetGetMethod(bool nonPublic) { return _property.GetMethod.AsMethodInfo(_metadataLoadContext); } public override ParameterInfo[] GetIndexParameters() { List parameters = default; foreach (var p in _property.Parameters) { parameters ??= new(); parameters.Add(p.AsParameterInfo(_metadataLoadContext)); } return parameters?.ToArray() ?? Array.Empty(); } public override MethodInfo GetSetMethod(bool nonPublic) { return _property.SetMethod.AsMethodInfo(_metadataLoadContext); } public override object GetValue(object obj, BindingFlags invokeAttr, Binder binder, object[] index, CultureInfo culture) { throw new NotSupportedException(); } public override bool IsDefined(Type attributeType, bool inherit) { throw new NotImplementedException(); } public override void SetValue(object obj, object value, BindingFlags invokeAttr, Binder binder, object[] index, CultureInfo culture) { throw new NotSupportedException(); } } } #nullable restore ================================================ FILE: src/uController.SourceGenerator/Reflection/RoslynType.cs ================================================ using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Reflection; using Microsoft.CodeAnalysis; #nullable disable namespace Roslyn.Reflection { internal class RoslynType : Type { private readonly ITypeSymbol _typeSymbol; private readonly MetadataLoadContext _metadataLoadContext; private readonly bool _isByRef; private TypeAttributes? _typeAttributes; public RoslynType(ITypeSymbol typeSymbol, MetadataLoadContext metadataLoadContext, bool isByRef = false) { _typeSymbol = typeSymbol; _metadataLoadContext = metadataLoadContext; _isByRef = isByRef; } public override Assembly Assembly => _typeSymbol.ContainingAssembly.AsAssembly(_metadataLoadContext); public override string AssemblyQualifiedName => throw new NotImplementedException(); public override Type BaseType => _typeSymbol.BaseType.AsType(_metadataLoadContext); public override string FullName => Namespace is null ? Name : Namespace + "." + Name; public override Guid GUID => Guid.Empty; public override Module Module => throw new NotImplementedException(); public override string Namespace => _typeSymbol.ContainingNamespace?.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat.WithGlobalNamespaceStyle(SymbolDisplayGlobalNamespaceStyle.Omitted)) is { Length: > 0 } ns ? ns : null; public override Type UnderlyingSystemType => this; public override string Name => ArrayTypeSymbol is { } ar ? ar.ElementType.MetadataName + "[]" : _typeSymbol.MetadataName; public override bool IsGenericType => NamedTypeSymbol?.IsGenericType ?? false; private INamedTypeSymbol NamedTypeSymbol => _typeSymbol as INamedTypeSymbol; private IArrayTypeSymbol ArrayTypeSymbol => _typeSymbol as IArrayTypeSymbol; public override bool IsGenericTypeDefinition => IsGenericType && SymbolEqualityComparer.IncludeNullability.Equals(NamedTypeSymbol, NamedTypeSymbol.ConstructedFrom); public override bool IsGenericParameter => _typeSymbol.TypeKind == TypeKind.TypeParameter; public ITypeSymbol TypeSymbol => _typeSymbol; public override bool IsEnum => _typeSymbol.TypeKind == TypeKind.Enum; public override bool IsConstructedGenericType => NamedTypeSymbol?.IsUnboundGenericType == false; public override Type DeclaringType => _typeSymbol.ContainingType?.AsType(_metadataLoadContext); public override int GetArrayRank() { return ArrayTypeSymbol.Rank; } public override Type[] GetGenericArguments() { if (NamedTypeSymbol is null) return Array.Empty(); var args = new List(); foreach (var item in NamedTypeSymbol.TypeArguments) { args.Add(item.AsType(_metadataLoadContext)); } return args.ToArray(); } public override Type GetGenericTypeDefinition() { return NamedTypeSymbol?.ConstructedFrom.AsType(_metadataLoadContext) ?? throw new NotSupportedException(); } public override IList GetCustomAttributesData() { return SharedUtilities.GetCustomAttributesData(_typeSymbol, _metadataLoadContext); } public override ConstructorInfo[] GetConstructors(BindingFlags bindingAttr) { if (NamedTypeSymbol is null) { return Array.Empty(); } List ctors = default; foreach (var c in NamedTypeSymbol.Constructors) { if (!SharedUtilities.MatchBindingFlags(bindingAttr, _typeSymbol, c)) { continue; } ctors ??= new(); ctors.Add(c.AsConstructorInfo(_metadataLoadContext)); } return ctors?.ToArray() ?? Array.Empty(); } public override Type MakeByRefType() { return new RoslynType(_typeSymbol, _metadataLoadContext, isByRef: true); } public override object[] GetCustomAttributes(bool inherit) { throw new NotSupportedException(); } public override object[] GetCustomAttributes(Type attributeType, bool inherit) { throw new NotSupportedException(); } public override Type MakeArrayType() { return _metadataLoadContext.Compilation.CreateArrayTypeSymbol(_typeSymbol).AsType(_metadataLoadContext); } public override Type MakeGenericType(params Type[] typeArguments) { if (!IsGenericTypeDefinition) { throw new NotSupportedException(); } var typeSymbols = new ITypeSymbol[typeArguments.Length]; for (int i = 0; i < typeArguments.Length; i++) { typeSymbols[i] = _metadataLoadContext.ResolveType(typeArguments[i]).GetTypeSymbol(); } return NamedTypeSymbol.Construct(typeSymbols).AsType(_metadataLoadContext); } public override Type GetElementType() { return ArrayTypeSymbol?.ElementType.AsType(_metadataLoadContext); } public override EventInfo GetEvent(string name, BindingFlags bindingAttr) { throw new NotImplementedException(); } public override EventInfo[] GetEvents(BindingFlags bindingAttr) { throw new NotImplementedException(); } public override FieldInfo GetField(string name, BindingFlags bindingAttr) { foreach (var symbol in _typeSymbol.GetMembers()) { if (symbol is not IFieldSymbol fieldSymbol) { continue; } if (!SharedUtilities.MatchBindingFlags(bindingAttr, _typeSymbol, symbol)) { continue; } return fieldSymbol.AsFieldInfo(_metadataLoadContext); } return null; } public override FieldInfo[] GetFields(BindingFlags bindingAttr) { List fields = default; foreach (var symbol in _typeSymbol.GetMembers()) { if (symbol is not IFieldSymbol fieldSymbol) { continue; } if (!SharedUtilities.MatchBindingFlags(bindingAttr, _typeSymbol, symbol)) { continue; } fields ??= new(); fields.Add(fieldSymbol.AsFieldInfo(_metadataLoadContext)); } return fields?.ToArray() ?? Array.Empty(); } public override Type GetInterface(string name, bool ignoreCase) { var comparison = ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal; foreach (var i in _typeSymbol.Interfaces) { if (i.Name.Equals(name, comparison)) { return i.AsType(_metadataLoadContext); } } return null; } public override Type[] GetInterfaces() { List interfaces = default; foreach (var i in _typeSymbol.Interfaces) { interfaces ??= new(); interfaces.Add(i.AsType(_metadataLoadContext)); } return interfaces?.ToArray() ?? Array.Empty(); } public override MemberInfo[] GetMembers(BindingFlags bindingAttr) { List members = null; foreach (var t in _typeSymbol.BaseTypes()) { foreach (var symbol in t.GetMembers()) { if (!SharedUtilities.MatchBindingFlags(bindingAttr, _typeSymbol, symbol)) { continue; } MemberInfo member = symbol switch { IFieldSymbol f => f.AsFieldInfo(_metadataLoadContext), IPropertySymbol p => p.AsPropertyInfo(_metadataLoadContext), IMethodSymbol c when c.MethodKind == MethodKind.Constructor => c.AsConstructorInfo(_metadataLoadContext), IMethodSymbol m => m.AsMethodInfo(_metadataLoadContext), _ => null }; if (member is null) { continue; } members ??= new(); members.Add(member); } } // https://github.com/dotnet/runtime/blob/9ec7fc21862f3446c6c6f7dcfff275942e3884d3/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs#L2693-L2694 bindingAttr &= ~BindingFlags.Static; foreach (var type in GetNestedTypes(bindingAttr)) { if (type.IsInterface) { continue; } members ??= new(); members.Add(type); } return members?.ToArray() ?? Array.Empty(); } public override MethodInfo[] GetMethods(BindingFlags bindingAttr) { List methods = null; foreach (var t in _typeSymbol.BaseTypes()) { foreach (var m in t.GetMembers()) { if (m is not IMethodSymbol method || method.MethodKind == MethodKind.Constructor) { continue; } if (!SharedUtilities.MatchBindingFlags(bindingAttr, _typeSymbol, method)) { continue; } methods ??= new(); methods.Add(method.AsMethodInfo(_metadataLoadContext)); } } return methods?.ToArray() ?? Array.Empty(); } public override Type GetNestedType(string name, BindingFlags bindingAttr) { foreach (var type in _typeSymbol.GetTypeMembers(name)) { if (!SharedUtilities.MatchBindingFlags(bindingAttr, _typeSymbol, type)) { continue; } return type.AsType(_metadataLoadContext); } return null; } public override Type[] GetNestedTypes(BindingFlags bindingAttr) { List nestedTypes = default; foreach (var type in _typeSymbol.GetTypeMembers()) { if (!SharedUtilities.MatchBindingFlags(bindingAttr, _typeSymbol, type)) { continue; } nestedTypes ??= new(); nestedTypes.Add(type.AsType(_metadataLoadContext)); } return nestedTypes?.ToArray() ?? Array.Empty(); } public override PropertyInfo[] GetProperties(BindingFlags bindingAttr) { List properties = default; foreach (var t in _typeSymbol.BaseTypes()) { foreach (var symbol in t.GetMembers()) { if (symbol is not IPropertySymbol property) { continue; } if (!SharedUtilities.MatchBindingFlags(bindingAttr, _typeSymbol, symbol)) { continue; } properties ??= new(); properties.Add(new RoslynPropertyInfo(property, _metadataLoadContext)); } } return properties?.ToArray() ?? Array.Empty(); } public override object InvokeMember(string name, BindingFlags invokeAttr, Binder binder, object target, object[] args, ParameterModifier[] modifiers, CultureInfo culture, string[] namedParameters) { throw new NotSupportedException(); } public override bool IsDefined(Type attributeType, bool inherit) { throw new NotSupportedException(); } protected override TypeAttributes GetAttributeFlagsImpl() { if (!_typeAttributes.HasValue) { _typeAttributes = default(TypeAttributes); if (_typeSymbol.IsAbstract) { _typeAttributes |= TypeAttributes.Abstract; } if (_typeSymbol.TypeKind == TypeKind.Interface) { _typeAttributes |= TypeAttributes.Interface; } if (_typeSymbol.IsSealed) { _typeAttributes |= TypeAttributes.Sealed; } bool isNested = _typeSymbol.ContainingType != null; switch (_typeSymbol.DeclaredAccessibility) { case Accessibility.NotApplicable: case Accessibility.Private: _typeAttributes |= isNested ? TypeAttributes.NestedPrivate : TypeAttributes.NotPublic; break; case Accessibility.ProtectedAndInternal: _typeAttributes |= isNested ? TypeAttributes.NestedFamANDAssem : TypeAttributes.NotPublic; break; case Accessibility.Protected: _typeAttributes |= isNested ? TypeAttributes.NestedFamily : TypeAttributes.NotPublic; break; case Accessibility.Internal: _typeAttributes |= isNested ? TypeAttributes.NestedAssembly : TypeAttributes.NotPublic; break; case Accessibility.ProtectedOrInternal: _typeAttributes |= isNested ? TypeAttributes.NestedFamORAssem : TypeAttributes.NotPublic; break; case Accessibility.Public: _typeAttributes |= isNested ? TypeAttributes.NestedPublic : TypeAttributes.Public; break; } } return _typeAttributes.Value; } protected override ConstructorInfo GetConstructorImpl(BindingFlags bindingAttr, Binder binder, CallingConventions callConvention, Type[] types, ParameterModifier[] modifiers) { // TODO: Use callConvention and modifiers StringComparison comparison = (bindingAttr & BindingFlags.IgnoreCase) == BindingFlags.IgnoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal; foreach (var m in _typeSymbol.GetMembers()) { if (m is not IMethodSymbol method || method.MethodKind != MethodKind.Constructor) { // Only methods that are constructors continue; } if (!SharedUtilities.MatchBindingFlags(bindingAttr, _typeSymbol, m)) { continue; } var valid = true; if (types is { Length: > 0 }) { var parameterCount = types.Length; // Compare parameter types if (parameterCount != method.Parameters.Length) { continue; } for (int i = 0; i < parameterCount; i++) { var parameterType = types[i]; var parameterTypeSymbol = _metadataLoadContext.ResolveType(parameterType)?.GetTypeSymbol(); if (parameterTypeSymbol is null) { valid = false; break; } if (!method.Parameters[i].Type.Equals(parameterTypeSymbol, SymbolEqualityComparer.Default)) { valid = false; break; } } } if (valid) { return new RoslynConstructorInfo(method, _metadataLoadContext); } } return null; } protected override MethodInfo GetMethodImpl(string name, BindingFlags bindingAttr, Binder binder, CallingConventions callConvention, Type[] types, ParameterModifier[] modifiers) { // TODO: Use callConvention and modifiers StringComparison comparison = (bindingAttr & BindingFlags.IgnoreCase) == BindingFlags.IgnoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal; foreach (var m in _typeSymbol.GetMembers()) { if (m is not IMethodSymbol method || method.MethodKind == MethodKind.Constructor) { // Only methods that are not constructors continue; } if (!SharedUtilities.MatchBindingFlags(bindingAttr, _typeSymbol, m)) { continue; } if (!method.Name.Equals(name, comparison)) { continue; } var valid = true; if (types is { Length: > 0 }) { var parameterCount = types.Length; // Compare parameter types if (parameterCount != method.Parameters.Length) { continue; } for (int i = 0; i < parameterCount; i++) { var parameterType = types[i]; var parameterTypeSymbol = _metadataLoadContext.ResolveType(parameterType)?.GetTypeSymbol(); if (parameterTypeSymbol is null) { valid = false; break; } if (!method.Parameters[i].Type.Equals(parameterTypeSymbol, SymbolEqualityComparer.Default)) { valid = false; break; } } } if (valid) { return method.AsMethodInfo(_metadataLoadContext); } } return null; } protected override PropertyInfo GetPropertyImpl(string name, BindingFlags bindingAttr, Binder binder, Type returnType, Type[] types, ParameterModifier[] modifiers) { StringComparison comparison = (bindingAttr & BindingFlags.IgnoreCase) == BindingFlags.IgnoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal; foreach (var symbol in _typeSymbol.GetMembers()) { if (symbol is not IPropertySymbol property) { continue; } if (!SharedUtilities.MatchBindingFlags(bindingAttr, _typeSymbol, symbol)) { continue; } if (!property.Name.Equals(name, comparison)) { continue; } var roslynReturnType = _metadataLoadContext.ResolveType(returnType); if (roslynReturnType?.Equals(property.Type) == false) { continue; } if (types is { Length: > 0 }) { var parameterCount = types.Length; // Compare parameter types if (parameterCount != property.Parameters.Length) { continue; } } // TODO: Use parameters return property.AsPropertyInfo(_metadataLoadContext); } return null; } protected override bool HasElementTypeImpl() { return ArrayTypeSymbol is not null; } protected override bool IsArrayImpl() { return ArrayTypeSymbol is not null; } protected override bool IsByRefImpl() => _isByRef; protected override bool IsCOMObjectImpl() { throw new NotImplementedException(); } protected override bool IsPointerImpl() { return _typeSymbol.Kind == SymbolKind.PointerType; } protected override bool IsPrimitiveImpl() { // Is IsPrimitive // https://github.com/dotnet/runtime/blob/55e95c80a7d7ec9d7bbbd5ad434604a1dc33e19c/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoType.TypeClassification.cs#L85 return _typeSymbol.SpecialType switch { SpecialType.System_Boolean => true, SpecialType.System_Char => true, SpecialType.System_SByte => true, SpecialType.System_Byte => true, SpecialType.System_Int16 => true, SpecialType.System_UInt16 => true, SpecialType.System_Int32 => true, SpecialType.System_UInt32 => true, SpecialType.System_Int64 => true, SpecialType.System_UInt64 => true, SpecialType.System_Single => true, SpecialType.System_Double => true, SpecialType.System_String => true, SpecialType.System_IntPtr => true, SpecialType.System_UIntPtr => true, _ => false }; } public override string ToString() { return _typeSymbol.ToString(); } public override bool IsAssignableFrom(Type c) { var otherTypeSymbol = c switch { RoslynType rt => rt._typeSymbol, Type t when _metadataLoadContext.ResolveType(t) is RoslynType rt => rt._typeSymbol, _ => null }; if (otherTypeSymbol is null) { return false; } return otherTypeSymbol.AllInterfaces.Contains(_typeSymbol, SymbolEqualityComparer.Default) || (otherTypeSymbol is INamedTypeSymbol ns && ns.BaseTypes().Contains(_typeSymbol, SymbolEqualityComparer.Default)); } public override int GetHashCode() { return SymbolEqualityComparer.Default.GetHashCode(_typeSymbol); } public override bool Equals(object o) { var otherTypeSymbol = o switch { RoslynType rt => rt._typeSymbol, Type t when _metadataLoadContext.ResolveType(t) is RoslynType rt => rt._typeSymbol, ITypeSymbol ts => ts, _ => null }; return _typeSymbol.Equals(otherTypeSymbol, SymbolEqualityComparer.Default); } public override bool Equals(Type o) { var otherTypeSymbol = o switch { RoslynType rt => rt._typeSymbol, Type t when _metadataLoadContext.ResolveType(t) is RoslynType rt => rt._typeSymbol, _ => null }; return _typeSymbol.Equals(otherTypeSymbol, SymbolEqualityComparer.Default); } } } #nullable restore ================================================ FILE: src/uController.SourceGenerator/Reflection/SharedUtilities.cs ================================================ using System; using System.Collections.Generic; using System.Reflection; using Microsoft.CodeAnalysis; #nullable disable namespace Roslyn.Reflection { internal class SharedUtilities { public static IList GetCustomAttributesData(ISymbol symbol, MetadataLoadContext metadataLoadContext) { List attributes = default; foreach (var a in symbol.GetAttributes()) { attributes ??= new(); attributes.Add(new RoslynCustomAttributeData(a, metadataLoadContext)); } return (IList)attributes ?? Array.Empty(); } public static MethodAttributes GetMethodAttributes(IMethodSymbol method) { MethodAttributes attributes = default; if (method.IsAbstract) { attributes |= MethodAttributes.Abstract | MethodAttributes.Virtual; } if (method.IsStatic) { attributes |= MethodAttributes.Static; } if (method.IsVirtual || method.IsOverride) { attributes |= MethodAttributes.Virtual; } switch (method.DeclaredAccessibility) { case Accessibility.Public: attributes |= MethodAttributes.Public; break; case Accessibility.Private: attributes |= MethodAttributes.Private; break; case Accessibility.Internal: attributes |= MethodAttributes.Assembly; break; } if (method.MethodKind != MethodKind.Ordinary) { attributes |= MethodAttributes.SpecialName; } return attributes; } public static bool MatchBindingFlags(BindingFlags bindingFlags, ITypeSymbol thisType, ISymbol symbol) { var isPublic = (symbol.DeclaredAccessibility & Accessibility.Public) == Accessibility.Public; var isNonProtectedInternal = (symbol.DeclaredAccessibility & Accessibility.ProtectedOrInternal) == 0; var isStatic = symbol.IsStatic; var isInherited = !SymbolEqualityComparer.Default.Equals(thisType, symbol.ContainingType); // TODO: REVIEW precomputing binding flags // From https://github.com/dotnet/runtime/blob/9ec7fc21862f3446c6c6f7dcfff275942e3884d3/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs#L2058 //var symbolBindingFlags = ComputeBindingFlags(isPublic, isStatic, isInherited); //if (symbol is ITypeSymbol && !isStatic) //{ // symbolBindingFlags &= ~BindingFlags.Instance; //} // The below logic is a mishmash of copied logic from the following // https://github.com/dotnet/runtime/blob/9ec7fc21862f3446c6c6f7dcfff275942e3884d3/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs#L2261 // filterFlags ^= BindingFlags.DeclaredOnly; // https://github.com/dotnet/runtime/blob/9ec7fc21862f3446c6c6f7dcfff275942e3884d3/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs#L2153 //if ((filterFlags & symbolBindingFlags) != symbolBindingFlags) //{ // return false; //} // Filter by Public & Private if (isPublic) { if ((bindingFlags & BindingFlags.Public) == 0) { return false; } } else { if ((bindingFlags & BindingFlags.NonPublic) == 0) { return false; } } // Filter by DeclaredOnly if ((bindingFlags & BindingFlags.DeclaredOnly) != 0 && isInherited) { return false; } if (symbol is not ITypeSymbol) { if (isStatic) { if ((bindingFlags & BindingFlags.FlattenHierarchy) == 0 && isInherited) { return false; } if ((bindingFlags & BindingFlags.Static) == 0) { return false; } } else { if ((bindingFlags & BindingFlags.Instance) == 0) { return false; } } } // @Asymmetry - Internal, inherited, instance, non -protected, non-virtual, non-abstract members returned // iff BindingFlags !DeclaredOnly, Instance and Public are present except for fields if (((bindingFlags & BindingFlags.DeclaredOnly) == 0) && // DeclaredOnly not present isInherited && // Is inherited Member isNonProtectedInternal && // Is non-protected internal member ((bindingFlags & BindingFlags.NonPublic) != 0) && // BindingFlag.NonPublic present (!isStatic) && // Is instance member ((bindingFlags & BindingFlags.Instance) != 0)) // BindingFlag.Instance present { if (symbol is not IMethodSymbol method) { return false; } if (!method.IsVirtual && !method.IsAbstract) { return false; } } return true; } public static BindingFlags ComputeBindingFlags(MemberInfo member) { if (member is PropertyInfo p) { return ComputeBindingFlags(p.GetMethod ?? p.SetMethod); } var (isPublic, isStatic) = member switch { FieldInfo f => (f.IsPublic, f.IsStatic), MethodInfo m => (m.IsPublic, m.IsStatic), _ => throw new NotSupportedException() }; var isInherited = member.ReflectedType != member.DeclaringType; return ComputeBindingFlags(isPublic, isStatic, isInherited); } private static BindingFlags ComputeBindingFlags(bool isPublic, bool isStatic, bool isInherited) { BindingFlags bindingFlags = isPublic ? BindingFlags.Public : BindingFlags.NonPublic; if (isInherited) { // We arrange things so the DeclaredOnly flag means "include inherited members" bindingFlags |= BindingFlags.DeclaredOnly; if (isStatic) { bindingFlags |= BindingFlags.Static | BindingFlags.FlattenHierarchy; } else { bindingFlags |= BindingFlags.Instance; } } else { if (isStatic) { bindingFlags |= BindingFlags.Static; } else { bindingFlags |= BindingFlags.Instance; } } return bindingFlags; } } } #nullable restore ================================================ FILE: src/uController.SourceGenerator/ReflectionExtensions.cs ================================================ using System; using System.Linq; using System.Reflection; namespace uController { internal static class ReflectionExtensions { public static CustomAttributeData GetCustomAttributeData(this MemberInfo memberInfo, Type type) { return memberInfo.CustomAttributes.FirstOrDefault(a => type.IsAssignableFrom(a.AttributeType)); } public static CustomAttributeData GetCustomAttributeData(this ParameterInfo paramterInfo, Type type) { return paramterInfo.CustomAttributes.FirstOrDefault(a => type.IsAssignableFrom(a.AttributeType)); } public static TValue GetConstructorArgument(this CustomAttributeData customAttributeData, int index) { return index < customAttributeData.ConstructorArguments.Count ? (TValue)customAttributeData.ConstructorArguments[index].Value : default; } public static TValue GetNamedArgument(this CustomAttributeData customAttributeData, string name) { return (TValue)customAttributeData.NamedArguments.FirstOrDefault(a => a.MemberName == name).TypedValue.Value; } } } ================================================ FILE: src/uController.SourceGenerator/RoutePattern.cs ================================================ using System; using System.Collections.Generic; using System.Linq; namespace uController.SourceGenerator { class RoutePattern { private static readonly char[] Slash = new[] { '/' }; public string Pattern { get; } private string[] _parameterNames; public RoutePattern(string pattern, string[] parameterNames) { Pattern = pattern; _parameterNames = parameterNames; } public bool HasParameter(string name) => _parameterNames.Contains(name); public override string ToString() => Pattern; public static RoutePattern Parse(string pattern) { if (pattern is null) { return null; } var segments = pattern.Split(Slash, StringSplitOptions.RemoveEmptyEntries); List parameters = null; foreach (var s in segments) { // Ignore complex segments and escaping var start = s.IndexOf('{'); if (start != -1) { var end = s.IndexOf('}', start + 1); if (end == -1) { continue; } var p = s.Substring(start + 1, end - start - 1); var constraintToken = p.IndexOf(':'); if (constraintToken != -1) { // Remove the constraint p = p.Substring(0, constraintToken); } parameters ??= new(); parameters.Add(p); } } return new RoutePattern(pattern, parameters?.ToArray() ?? Array.Empty()); } } } ================================================ FILE: src/uController.SourceGenerator/WellKnownTypes.cs ================================================ using System; using System.Reflection; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Metadata; using Microsoft.AspNetCore.Routing; using Roslyn.Reflection; namespace uController.SourceGenerator { internal class WellKnownTypes { public WellKnownTypes(MetadataLoadContext metadataLoadContext) { // REVIEW: Consider making this lazy FromQueryMetadataType = metadataLoadContext.ResolveType(); FromRouteMetadataType = metadataLoadContext.ResolveType(); FromHeaderMetadataType = metadataLoadContext.ResolveType(); FromFormMetadataType = metadataLoadContext.ResolveType(); FromBodyMetadataType = metadataLoadContext.ResolveType(); FromServicesMetadataType = metadataLoadContext.ResolveType(); AsParametersAttributeType = metadataLoadContext.ResolveType(); IEndpointMetadataProviderType = metadataLoadContext.ResolveType(); IEndpointParameterMetadataProviderType = metadataLoadContext.ResolveType(); EndpointRouteBuilderType = metadataLoadContext.ResolveType(); DelegateType = metadataLoadContext.ResolveType(); IResultType = metadataLoadContext.ResolveType(); HttpContextType = metadataLoadContext.ResolveType(); ParamterInfoType = metadataLoadContext.ResolveType(); IFormatProviderType = metadataLoadContext.ResolveType(); EnumType = metadataLoadContext.ResolveType(); ResultsType = metadataLoadContext.ResolveType(); TypedResultsType = metadataLoadContext.ResolveType(); SourceKeyType = metadataLoadContext.ResolveType("Microsoft.AspNetCore.Builder.SourceKey"); } public Type FromQueryMetadataType { get; } public Type FromRouteMetadataType { get; } public Type FromHeaderMetadataType { get; } public Type FromFormMetadataType { get; } public Type FromBodyMetadataType { get; } public Type FromServicesMetadataType { get; } public Type AsParametersAttributeType { get; } public Type IEndpointMetadataProviderType { get; } public Type IEndpointParameterMetadataProviderType { get; } public Type EndpointRouteBuilderType { get; } public Type DelegateType { get; } public Type IResultType { get; } public Type HttpContextType { get; } public Type ParamterInfoType { get; } public Type IFormatProviderType { get; } public Type EnumType { get; } public Type ResultsType { get; } public Type TypedResultsType { get; } public Type SourceKeyType { get; } } } ================================================ FILE: src/uController.SourceGenerator/uController.SourceGenerator.csproj ================================================  netstandard2.0 9.0 The compile time code generator for Minimal APIs David Fowler false https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet5/nuget/v3/index.json ;$(RestoreAdditionalProjectSources) ================================================ FILE: src/uController.SourceGenerator/uControllerGenerator.cs ================================================ using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; using System.Reflection; using System.Text; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Operations; using Microsoft.CodeAnalysis.Text; using Microsoft.Extensions.Internal; using Roslyn.Reflection; namespace uController.SourceGenerator { [Generator] public class uControllerGenerator : ISourceGenerator { private static readonly Dictionary MethodDescriptions = new() { ["MapGet"] = "Get", ["MapPost"] = "Post", ["MapPut"] = "Put", ["MapDelete"] = "Delete", ["MapPatch"] = "Patch" }; public void Execute(GeneratorExecutionContext context) { if (context.SyntaxReceiver is not SyntaxReceiver receiver) { // nothing to do yet return; } if (Environment.GetEnvironmentVariable("UCONTROLLER_DEBUG") == "1") { System.Diagnostics.Debugger.Launch(); } var metadataLoadContext = new MetadataLoadContext(context.Compilation); var wellKnownTypes = new WellKnownTypes(metadataLoadContext); var sb = new StringBuilder(); var thunks = new StringBuilder(); var genericThunks = new StringBuilder(); var generatedMethodSignatures = new HashSet(); var knownTypedResultsMethods = wellKnownTypes.TypedResultsType?.GetMethods(BindingFlags.Public | BindingFlags.Static) .ToLookup(m => (m.Name, m.IsGenericMethod)); foreach (var invocation in receiver.MapActions) { var semanticModel = context.Compilation.GetSemanticModel(invocation.SyntaxTree); var operation = semanticModel.GetOperation(invocation); if (operation is IInvocationOperation { Arguments: { Length: 3 } parameters } invocationOperation && wellKnownTypes.DelegateType.Equals(parameters[2].Parameter.Type) && wellKnownTypes.EndpointRouteBuilderType.Equals(parameters[0].Parameter.Type)) { // We only want to generate overloads for calls that have a Delegate parameter } else { continue; } var callName = invocationOperation.TargetMethod.Name; var routePatternArgument = invocationOperation.Arguments[1]; var delegateArgument = invocationOperation.Arguments[2]; IOperation ResolveDeclarationOperation(ISymbol symbol) { foreach (var syntaxReference in symbol.DeclaringSyntaxReferences) { var syn = syntaxReference.GetSyntax(); if (syn is VariableDeclaratorSyntax { Initializer: { Value: var expr } }) { // Use the correct semantic model based on the syntax tree var operation = context.Compilation.GetSemanticModel(syn.SyntaxTree).GetOperation(expr); if (operation is not null) { return operation; } } } return null; } // Could be rewritten as a while loop IMethodSymbol ResolveMethodFromOperation(IOperation operation) => operation switch { IArgumentOperation argument => ResolveMethodFromOperation(argument.Value), IConversionOperation conv => ResolveMethodFromOperation(conv.Operand), IDelegateCreationOperation del => ResolveMethodFromOperation(del.Target), IFieldReferenceOperation f when f.Field.IsReadOnly && ResolveDeclarationOperation(f.Field) is IOperation op => ResolveMethodFromOperation(op), IAnonymousFunctionOperation anon => anon.Symbol, ILocalFunctionOperation local => local.Symbol, IMethodReferenceOperation method => method.Method, _ => null }; var method = ResolveMethodFromOperation(delegateArgument); if (method == null) { context.ReportDiagnostic(Diagnostic.Create(Diagnostics.UnknownDelegateType, delegateArgument.Syntax.GetLocation(), delegateArgument.Syntax.ToFullString())); continue; } object ResolveLiteralOperation(IOperation operation) => operation switch { IArgumentOperation argument => ResolveLiteralOperation(argument.Value), ILiteralOperation literal => literal.ConstantValue.Value, ILocalReferenceOperation l when l.Local.IsConst && ResolveDeclarationOperation(l.Local) is IOperation op => ResolveLiteralOperation(op), IFieldReferenceOperation f when f.Field.IsReadOnly && ResolveDeclarationOperation(f.Field) is IOperation op => ResolveLiteralOperation(op), _ => null }; var routePattern = ResolveLiteralOperation(routePatternArgument) as string; var methodModel = new MethodModel { UniqueName = "RequestHandler", MethodInfo = method.AsMethodInfo(metadataLoadContext), RoutePattern = RoutePattern.Parse(routePattern) }; var parameterIndex = 0; foreach (var parameter in methodModel.MethodInfo.GetParameters()) { var fromQuery = parameter.GetCustomAttributeData(wellKnownTypes.FromQueryMetadataType); var fromHeader = parameter.GetCustomAttributeData(wellKnownTypes.FromHeaderMetadataType); var fromForm = parameter.GetCustomAttributeData(wellKnownTypes.FromFormMetadataType); var fromBody = parameter.GetCustomAttributeData(wellKnownTypes.FromBodyMetadataType); var fromRoute = parameter.GetCustomAttributeData(wellKnownTypes.FromRouteMetadataType); var fromService = parameter.GetCustomAttributeData(wellKnownTypes.FromServicesMetadataType); var asParameters = parameter.GetCustomAttributeData(wellKnownTypes.AsParametersAttributeType); var parameterModel = new ParameterModel { Method = methodModel, ParameterSymbol = parameter.GetParameterSymbol(), ParameterInfo = parameter, Name = parameter.Name, GeneratedName = "arg_" + parameter.Name, ParameterType = parameter.ParameterType, FromQuery = fromQuery == null ? null : fromQuery?.GetNamedArgument("Name") ?? parameter.Name, FromHeader = fromHeader == null ? null : fromHeader?.GetNamedArgument("Name") ?? parameter.Name, FromForm = fromForm == null ? null : fromForm?.GetNamedArgument("Name") ?? parameter.Name, FromRoute = fromRoute == null ? null : fromRoute?.GetNamedArgument("Name") ?? parameter.Name, FromBodyAttributeData = fromBody, FromServices = fromService != null, Index = parameterIndex }; if (methodModel.RoutePattern is { } pattern) { if (pattern.HasParameter(parameter.Name)) { parameterModel.FromRoute = parameter.Name; } } methodModel.Parameters.Add(parameterModel); parameterIndex++; } var codeGenerator = new MinimalCodeGenerator(wellKnownTypes); for (int i = 0; i < 4; i++) { codeGenerator.Indent(); } codeGenerator.Generate(methodModel); if (codeGenerator.BodyParameters.Count > 1) { var mainLocation = (method.DeclaringSyntaxReferences[0].GetSyntax() switch { MethodDeclarationSyntax methodDeclarationSyntax => methodDeclarationSyntax.Identifier.GetLocation(), LocalFunctionStatementSyntax localFunctionStatementSyntax => localFunctionStatementSyntax.Identifier.GetLocation(), var expr => expr.GetLocation() }); var otherLocations = new List(); foreach (var p in codeGenerator.BodyParameters) { foreach (var syntaxReference in p.ParameterSymbol.DeclaringSyntaxReferences) { otherLocations.Add(syntaxReference.GetSyntax().GetLocation()); } p.Unresovled = true; } context.ReportDiagnostic(Diagnostic.Create(Diagnostics.MultipleParametersConsumingBody, mainLocation, otherLocations)); } var preReq = new StringBuilder(); var runtimeChecks = new StringBuilder(); var generatedRoutePatternVars = false; var generatedBodyOrService = false; var generatedParameterInfos = false; foreach (var p in methodModel.Parameters) { if (p.Unresovled) { var loc = p.ParameterSymbol.DeclaringSyntaxReferences[0].GetSyntax().GetLocation(); if (p.HasBindingSource && !p.FromBody) { context.ReportDiagnostic(Diagnostic.Create(Diagnostics.UnableToResolveTryParseForType, loc, p.ParameterType.FullName)); } else { context.ReportDiagnostic(Diagnostic.Create(Diagnostics.UnableToResolveParameter, loc, p.Name)); } } if (p.QueryOrRoute) { if (!generatedRoutePatternVars) { generatedRoutePatternVars = true; preReq.AppendLine(" var routePattern = (builder as RouteEndpointBuilder)?.RoutePattern;"); } runtimeChecks.AppendLine($@" System.Func {p.GeneratedName}RouteOrQueryResolver = routePattern?.GetParameter(""{p.Name}"") is null ? ResolveByQuery : ResolveByRoute;"); } if (p.BodyOrService) { if (!generatedBodyOrService) { generatedBodyOrService = true; preReq.AppendLine(" var ispis = builder.ApplicationServices.GetService();"); } var isOptional = p.ParameterSymbol.IsOptional || p.ParameterSymbol.NullableAnnotation == NullableAnnotation.Annotated; var resolveBody = isOptional ? $"ResolveBodyOptional<{p.ParameterType}>" : $"ResolveBodyRequired<{p.ParameterType}>"; runtimeChecks.AppendLine($@" System.Func> {p.GeneratedName}ServiceOrBodyResolver = (ispis?.IsService(typeof({p.ParameterType.ToString().Replace("?", string.Empty)})) ?? false) ? ResolveService<{p.ParameterType}>({isOptional.ToString().ToLower()}) : {resolveBody};"); } if (p.RequiresParameterInfo) { if (!generatedParameterInfos) { generatedParameterInfos = true; preReq.AppendLine(" var parameterInfos = del.Method.GetParameters();"); } runtimeChecks.AppendLine($@" var {p.GeneratedName}ParameterInfo = parameterInfos[{p.Index}];"); } } var hasAnonymoysParameterType = false; // List of parameters and return type var types = new List(); foreach (var p in method.Parameters) { if (p.Type.IsAnonymousType) { var loc = p.DeclaringSyntaxReferences[0].GetSyntax().GetLocation(); context.ReportDiagnostic(Diagnostic.Create(Diagnostics.AnonymousTypesAsParametersAreNotSupported, loc)); } types.Add(p.Type.ToDisplayString()); } if (hasAnonymoysParameterType) { // Don't generate this method continue; } if (method.ReturnType.IsAnonymousType) { types.Add("T"); } else { types.Add(method.ReturnType.ToDisplayString()); } var formattedTypeArgs = string.Join(", ", types); formattedTypeArgs = method.ReturnsVoid ? string.Join(", ", types.Take(types.Count - 1)) : formattedTypeArgs; var delegateType = method.ReturnsVoid ? "System.Action" : "System.Func"; var fullDelegateType = formattedTypeArgs.Length == 0 ? delegateType : $"{delegateType}<{formattedTypeArgs}>"; // REVIEW: Figure out why open generics don't work //var formattedOpenGenericArgs = string.Join(", ", (method.ReturnsVoid ? types.Take(types.Count - 1) : types).Select((t, i) => $"T{i}")); //formattedOpenGenericArgs = formattedOpenGenericArgs.Length == 0 ? formattedOpenGenericArgs : $"<{formattedOpenGenericArgs}>"; //var openGenericType = formattedOpenGenericArgs.Length == 0 ? delegateType : $"{delegateType}{formattedOpenGenericArgs}"; var filterArgumentString = string.Join(", ", types.Take(types.Count - 1).Select((t, i) => $"ic.GetArgument<{t}>({i})")); // Get the source location (file and line number) var span = invocation.SyntaxTree.GetLineSpan(invocation.Span); var lineNumber = span.StartLinePosition.Line + 1; var filteredInvocationText = method.ReturnsVoid ? $@"handler({filterArgumentString}); return System.Threading.Tasks.ValueTask.FromResult(Results.Empty);" : $@"return System.Threading.Tasks.ValueTask.FromResult(handler({filterArgumentString}));"; var populateMetadata = new StringBuilder(); var metadataPreReqs = new StringBuilder(); var generatedMetadataParameterInfo = false; var generatedIsServiceProvider = false; foreach (var p in methodModel.Parameters) { if (wellKnownTypes.IEndpointMetadataProviderType?.IsAssignableFrom(p.ParameterType) is true) { populateMetadata.AppendLine($@" PopulateMetadata<{p.ParameterType}>(del.Method, builder);"); } if (wellKnownTypes.IEndpointParameterMetadataProviderType?.IsAssignableFrom(p.ParameterType) is true) { if (!generatedMetadataParameterInfo) { metadataPreReqs.AppendLine(" var parameterInfos = del.Method.GetParameters();"); generatedMetadataParameterInfo = true; } populateMetadata.AppendLine($@" PopulateMetadata<{p.ParameterType}>(parameterInfos[{p.Index}], builder);"); } if (p.FromBody) { var acceptsType = $"{p.ParameterType}".Trim('?'); populateMetadata.AppendLine($@" builder.Metadata.Add(new AcceptsTypeMetadata(typeof({acceptsType}), true, new[] {{ ""application/json"" }}));"); } else if (p.BodyOrService) { var acceptsType = $"{p.ParameterType}".Trim('?'); if (!generatedIsServiceProvider) { metadataPreReqs.AppendLine($@" var ispis = builder.ApplicationServices.GetService();"); generatedIsServiceProvider = true; } populateMetadata.AppendLine($@" if ((ispis?.IsService(typeof({acceptsType})) ?? false) == false) builder.Metadata.Add(new AcceptsTypeMetadata(typeof({acceptsType}), true, new[] {{ ""application/json"" }}));"); } if (p.ReadFromForm) { populateMetadata.AppendLine($@" builder.Metadata.Add(new AcceptsTypeMetadata(typeof({p.ParameterType}), true, new[] {{ ""multipart/form-data"" }}));"); } } void AnalyzeResultTypesForIResultMethods(IMethodSymbol method, Type returnType) { if (!wellKnownTypes.IResultType.Equals(returnType)) { // Don't bother if we're not looking at an IResult returning method return; } foreach (var reference in method.DeclaringSyntaxReferences) { var syntax = reference.GetSyntax(); var operation = semanticModel.GetOperation(syntax); // TODO: This needs a real detailed analysis working from return expressions, this is a bit of a hack right now // looking for *any* results call in this method. This should find all exit points from a method // and start from there. foreach (var op in operation.Descendants().OfType()) { var resultsMethod = op.TargetMethod; if (resultsMethod.IsStatic && wellKnownTypes.ResultsType.Equals(resultsMethod.ContainingType)) { if (resultsMethod.Name == "StatusCode") { // Try to resolve the status code statically var literalExpression = ResolveLiteralOperation(op.Arguments[0].Value); if (literalExpression is not null) { populateMetadata.AppendLine($@" builder.Metadata.Add(ResponseTypeMetadata.Create({literalExpression}));"); } } else { var candidate = knownTypedResultsMethods[(resultsMethod.Name, resultsMethod.IsGenericMethod)].FirstOrDefault(); if (candidate is not null) { if (candidate.IsGenericMethod) { candidate = candidate.MakeGenericMethod(resultsMethod.AsMethodInfo(metadataLoadContext).GetGenericArguments()); } } if (wellKnownTypes.IEndpointMetadataProviderType?.IsAssignableFrom(candidate.ReturnType) == true) { populateMetadata.AppendLine($@" PopulateMetadata<{candidate.ReturnType}>(del.Method, builder);"); } } } } } } populateMetadata.AppendLine($@" builder.Metadata.Add(new SourceKey(@""{invocation.SyntaxTree.FilePath}"", {lineNumber}));"); var returnType = methodModel.MethodInfo.ReturnType; if (AwaitableInfo.IsTypeAwaitable(returnType, out var awaitableInfo)) { returnType = awaitableInfo.ResultType; } AnalyzeResultTypesForIResultMethods(method, returnType); if (returnType.Equals(typeof(void))) { // Don't add metadata } else if (wellKnownTypes.IEndpointMetadataProviderType?.IsAssignableFrom(returnType) == true) { // TODO: Result internally uses reflection to call this method on it's generic args conditionally // we can avoid that reflection here. // Static abstract call populateMetadata.AppendLine($@" PopulateMetadata<{returnType}>(del.Method, builder);"); } else if (returnType.Equals(typeof(string))) { // Add string plaintext populateMetadata.AppendLine($@" builder.Metadata.Add(ResponseTypeMetadata.Create(""text/plain""));"); } else if (!wellKnownTypes.IResultType.IsAssignableFrom(returnType)) { // Add JSON populateMetadata.AppendLine($@" builder.Metadata.Add(ResponseTypeMetadata.Create(""application/json"", {(returnType.GetTypeSymbol().IsAnonymousType ? "typeof(T)" : $"typeof({returnType.ToString().Replace("?", string.Empty)})")}));"); } var thunkBuilder = method.ReturnType.IsAnonymousType ? genericThunks : thunks; // Generate code here for this thunk thunkBuilder.Append($@" [(@""{invocation.SyntaxTree.FilePath}"", {lineNumber})] = ( (del, builder) => {{ {metadataPreReqs.ToString().TrimEnd()} {populateMetadata.ToString().TrimEnd()} }}, (del, builder) => {{ var handler = ({fullDelegateType})del; EndpointFilterDelegate? filteredInvocation = null; {preReq}{runtimeChecks.ToString().TrimEnd()} if (builder.FilterFactories.Count > 0) {{ filteredInvocation = BuildFilterDelegate(ic => {{ if (ic.HttpContext.Response.StatusCode == 400) {{ return System.Threading.Tasks.ValueTask.FromResult(Results.Empty); }} {filteredInvocationText} }}, builder, handler.Method); }} {codeGenerator} return filteredInvocation is null ? RequestHandler : RequestHandlerFiltered; }}), "); if (!generatedMethodSignatures.Add($"{callName}_{fullDelegateType}")) { continue; } var verbArgument = MethodDescriptions.TryGetValue(callName, out var verb) ? $"{verb}Verb" : "null"; string methodText = null; if (method.ReturnType.IsAnonymousType) { methodText = @$" /// /// Adds a to the that matches HTTP{(verb is not null ? " " + verb.ToUpperInvariant() : "")} requests /// for the specified pattern. /// /// The to add the route to. /// The route pattern. /// The delegate executed when the endpoint is matched. /// A that can be used to further customize the endpoint. internal static Microsoft.AspNetCore.Builder.RouteHandlerBuilder {callName}(this Microsoft.AspNetCore.Routing.IEndpointRouteBuilder endpoints, string pattern, {fullDelegateType} handler, [System.Runtime.CompilerServices.CallerFilePath] string filePath = """", [System.Runtime.CompilerServices.CallerLineNumber]int lineNumber = 0) {{ return MapCore(endpoints, pattern, handler, {verbArgument}, filePath, lineNumber); }} "; } else { methodText = @$" /// /// Adds a to the that matches HTTP{(verb is not null ? " " + verb.ToUpperInvariant() : "")} requests /// for the specified pattern. /// /// The to add the route to. /// The route pattern. /// The delegate executed when the endpoint is matched. /// A that can be used to further customize the endpoint. internal static Microsoft.AspNetCore.Builder.RouteHandlerBuilder {callName}(this Microsoft.AspNetCore.Routing.IEndpointRouteBuilder endpoints, string pattern, {fullDelegateType} handler, [System.Runtime.CompilerServices.CallerFilePath] string filePath = """", [System.Runtime.CompilerServices.CallerLineNumber]int lineNumber = 0) {{ return MapCore(endpoints, pattern, handler, {verbArgument}, filePath, lineNumber); }} "; } sb.Append(methodText); } string sourceKeyText = wellKnownTypes.SourceKeyType is not null ? "" : @" namespace Microsoft.AspNetCore.Builder { internal record SourceKey(string Path, int Line); } "; var mapActionsText = $@" //------------------------------------------------------------------------------ // // This code was generated by a tool. // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // //------------------------------------------------------------------------------ #if NET7_0_OR_GREATER #nullable enable using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Threading.Tasks; using System.IO; using Microsoft.AspNetCore.Routing; using Microsoft.AspNetCore.Routing.Patterns; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.FileProviders; using Microsoft.Extensions.Primitives; using MetadataPopulator = System.Action; using RequestDelegateFactoryFunc = System.Func; {sourceKeyText} internal static class GeneratedRouteBuilderExtensions {{ private static readonly string[] GetVerb = new[] {{ HttpMethods.Get }}; private static readonly string[] PostVerb = new[] {{ HttpMethods.Post }}; private static readonly string[] PutVerb = new[] {{ HttpMethods.Put }}; private static readonly string[] DeleteVerb = new[] {{ HttpMethods.Delete }}; private static readonly string[] PatchVerb = new[] {{ HttpMethods.Patch }}; private class GenericThunks {{ public static readonly System.Collections.Generic.Dictionary<(string, int), (MetadataPopulator, RequestDelegateFactoryFunc)> map = new() {{ {genericThunks} }}; }} private static readonly System.Collections.Generic.Dictionary<(string, int), (MetadataPopulator, RequestDelegateFactoryFunc)> map = new() {{ {thunks} }}; {sb.ToString().TrimEnd()} private static Microsoft.AspNetCore.Builder.RouteHandlerBuilder MapCore( this Microsoft.AspNetCore.Routing.IEndpointRouteBuilder routes, string pattern, System.Delegate handler, IEnumerable httpMethods, string filePath, int lineNumber) {{ var (populate, factory) = GenericThunks.map[(filePath, lineNumber)]; return GetOrAddRouteEndpointDataSource(routes).AddRouteHandler(RoutePatternFactory.Parse(pattern), handler, httpMethods, isFallback: false, populate, factory); }} private static Microsoft.AspNetCore.Builder.RouteHandlerBuilder MapCore( this Microsoft.AspNetCore.Routing.IEndpointRouteBuilder routes, string pattern, System.Delegate handler, IEnumerable httpMethods, string filePath, int lineNumber) {{ var (populate, factory) = map[(filePath, lineNumber)]; return GetOrAddRouteEndpointDataSource(routes).AddRouteHandler(RoutePatternFactory.Parse(pattern), handler, httpMethods, isFallback: false, populate, factory); }} private static SourceGeneratedRouteEndpointDataSource GetOrAddRouteEndpointDataSource(IEndpointRouteBuilder endpoints) {{ SourceGeneratedRouteEndpointDataSource? routeEndpointDataSource = null; foreach (var dataSource in endpoints.DataSources) {{ if (dataSource is SourceGeneratedRouteEndpointDataSource foundDataSource) {{ routeEndpointDataSource = foundDataSource; break; }} }} if (routeEndpointDataSource is null) {{ routeEndpointDataSource = new SourceGeneratedRouteEndpointDataSource(endpoints.ServiceProvider); endpoints.DataSources.Add(routeEndpointDataSource); }} return routeEndpointDataSource; }} private static EndpointFilterDelegate BuildFilterDelegate(EndpointFilterDelegate filteredInvocation, EndpointBuilder builder, System.Reflection.MethodInfo mi) {{ var routeHandlerFilters = builder.FilterFactories; var context0 = new EndpointFilterFactoryContext {{ MethodInfo = mi, ApplicationServices = builder.ApplicationServices, }}; var initialFilteredInvocation = filteredInvocation; for (var i = routeHandlerFilters.Count - 1; i >= 0; i--) {{ var filterFactory = routeHandlerFilters[i]; filteredInvocation = filterFactory(context0, filteredInvocation); }} return filteredInvocation; }} private static void PopulateMetadata(System.Reflection.MethodInfo method, EndpointBuilder builder) where T : Microsoft.AspNetCore.Http.Metadata.IEndpointMetadataProvider {{ T.PopulateMetadata(method, builder); }} private static void PopulateMetadata(System.Reflection.ParameterInfo parameter, EndpointBuilder builder) where T : Microsoft.AspNetCore.Http.Metadata.IEndpointParameterMetadataProvider {{ T.PopulateMetadata(parameter, builder); }} private static Task ExecuteObjectResult(object obj, HttpContext httpContext) {{ if (obj is IResult r) {{ return r.ExecuteAsync(httpContext); }} else if (obj is string s) {{ return httpContext.Response.WriteAsync(s); }} else {{ return httpContext.Response.WriteAsJsonAsync(obj); }} }} private static Microsoft.Extensions.Primitives.StringValues? ResolveByQuery(HttpContext context, string key) => context.Request.Query[key]; private static Microsoft.Extensions.Primitives.StringValues? ResolveByRoute(HttpContext context, string key) => context.Request.RouteValues[key]?.ToString(); private static Func> ResolveService(bool isOptional) => isOptional ? (HttpContext httpContext) => new ValueTask(httpContext.RequestServices.GetService()) : (HttpContext httpContext) => new ValueTask(httpContext.RequestServices.GetRequiredService()); private static async ValueTask ResolveBodyOptional(HttpContext httpContext) => await ResolveBody(httpContext, true); private static async ValueTask ResolveBodyRequired(HttpContext httpContext) => await ResolveBody(httpContext, false); private static async ValueTask ResolveBody(HttpContext httpContext, bool allowEmpty) {{ var feature = httpContext.Features.Get(); if (feature?.CanHaveBody == true) {{ if (!httpContext.Request.HasJsonContentType()) {{ httpContext.Response.StatusCode = StatusCodes.Status415UnsupportedMediaType; return default; }} try {{ var bodyValue = await httpContext.Request.ReadFromJsonAsync(); if (!allowEmpty && bodyValue == null) {{ httpContext.Response.StatusCode = StatusCodes.Status400BadRequest; }} return bodyValue; }} catch (IOException) {{ return default; }} catch (System.Text.Json.JsonException) {{ httpContext.Response.StatusCode = StatusCodes.Status400BadRequest; return default; }} }} return default; }} private sealed class AcceptsTypeMetadata : Microsoft.AspNetCore.Http.Metadata.IAcceptsMetadata {{ public IReadOnlyList ContentTypes {{ get; }} public Type RequestType {{ get; }} public bool IsOptional {{ get; }} public AcceptsTypeMetadata(Type type, bool isOptional, string[] contentTypes) {{ RequestType = type ?? throw new ArgumentNullException(nameof(type)); if (contentTypes == null) {{ throw new ArgumentNullException(nameof(contentTypes)); }} ContentTypes = contentTypes; IsOptional = isOptional; }} }} private sealed class ResponseTypeMetadata : Microsoft.AspNetCore.Http.Metadata.IProducesResponseTypeMetadata {{ public Type Type {{ get; set; }} = typeof(void); public int StatusCode {{ get; set; }} = 200; public IEnumerable ContentTypes {{ get; init; }} = Enumerable.Empty(); public static ResponseTypeMetadata Create(string contentType, Type? type = null) {{ return new ResponseTypeMetadata {{ ContentTypes = new[] {{ contentType }}, Type = type }}; }} public static ResponseTypeMetadata Create(int statusCode) {{ return new ResponseTypeMetadata {{ StatusCode = statusCode }}; }} }} private sealed class SourceGeneratedRouteEndpointDataSource : EndpointDataSource {{ private readonly List _routeEntries = new(); private readonly IServiceProvider _applicationServices; public SourceGeneratedRouteEndpointDataSource(IServiceProvider applicationServices) {{ _applicationServices = applicationServices; }} public RouteHandlerBuilder AddRouteHandler( RoutePattern pattern, Delegate routeHandler, IEnumerable httpMethods, bool isFallback, MetadataPopulator metadataPopulator, RequestDelegateFactoryFunc requestDelegateFactoryFunc) {{ var conventions = new ThrowOnAddAfterEndpointBuiltConventionCollection(); var finallyConventions = new ThrowOnAddAfterEndpointBuiltConventionCollection(); var routeAttributes = RouteAttributes.RouteHandler; if (isFallback) {{ routeAttributes |= RouteAttributes.Fallback; }} _routeEntries.Add(new() {{ RoutePattern = pattern, RouteHandler = routeHandler, HttpMethods = httpMethods, RouteAttributes = routeAttributes, Conventions = conventions, FinallyConventions = finallyConventions, RequestDelegateFactory = requestDelegateFactoryFunc, MetadataPopulator = metadataPopulator, }}); return new RouteHandlerBuilder(new[] {{ new ConventionBuilder(conventions, finallyConventions) }}); }} public override IReadOnlyList Endpoints {{ get {{ var endpoints = new RouteEndpoint[_routeEntries.Count]; for (int i = 0; i < _routeEntries.Count; i++) {{ endpoints[i] = (RouteEndpoint)CreateRouteEndpointBuilder(_routeEntries[i]).Build(); }} return endpoints; }} }} public override IReadOnlyList GetGroupedEndpoints(RouteGroupContext context) {{ var endpoints = new RouteEndpoint[_routeEntries.Count]; for (int i = 0; i < _routeEntries.Count; i++) {{ endpoints[i] = (RouteEndpoint)CreateRouteEndpointBuilder(_routeEntries[i], context.Prefix, context.Conventions, context.FinallyConventions).Build(); }} return endpoints; }} public override IChangeToken GetChangeToken() => NullChangeToken.Singleton; private RouteEndpointBuilder CreateRouteEndpointBuilder( RouteEntry entry, RoutePattern? groupPrefix = null, IReadOnlyList>? groupConventions = null, IReadOnlyList>? groupFinallyConventions = null) {{ var pattern = RoutePatternFactory.Combine(groupPrefix, entry.RoutePattern); var handler = entry.RouteHandler; var isRouteHandler = (entry.RouteAttributes & RouteAttributes.RouteHandler) == RouteAttributes.RouteHandler; var isFallback = (entry.RouteAttributes & RouteAttributes.Fallback) == RouteAttributes.Fallback; var order = isFallback ? int.MaxValue : 0; var displayName = pattern.RawText ?? pattern.ToString(); if (entry.HttpMethods is not null) {{ // Prepends the HTTP method to the DisplayName produced with pattern + method name displayName = $""HTTP: {{string.Join("", "", entry.HttpMethods)}} {{displayName}}""; }} if (isFallback) {{ displayName = $""Fallback {{displayName}}""; }} // If we're not a route handler, we started with a fully realized (although unfiltered) RequestDelegate, so we can just redirect to that // while running any conventions. We'll put the original back if it remains unfiltered right before building the endpoint. RequestDelegate? factoryCreatedRequestDelegate = null; // Let existing conventions capture and call into builder.RequestDelegate as long as they do so after it has been created. RequestDelegate redirectRequestDelegate = context => {{ if (factoryCreatedRequestDelegate is null) {{ throw new InvalidOperationException(""Resources.RouteEndpointDataSource_RequestDelegateCannotBeCalledBeforeBuild""); }} return factoryCreatedRequestDelegate(context); }}; // Add MethodInfo and HttpMethodMetadata (if any) as first metadata items as they are intrinsic to the route much like // the pattern or default display name. This gives visibility to conventions like WithOpenApi() to intrinsic route details // (namely the MethodInfo) even when applied early as group conventions. RouteEndpointBuilder builder = new(redirectRequestDelegate, pattern, order) {{ DisplayName = displayName, ApplicationServices = _applicationServices, }}; if (isRouteHandler) {{ builder.Metadata.Add(handler.Method); }} if (entry.HttpMethods is not null) {{ builder.Metadata.Add(new HttpMethodMetadata(entry.HttpMethods)); }} // Apply group conventions before entry-specific conventions added to the RouteHandlerBuilder. if (groupConventions is not null) {{ foreach (var groupConvention in groupConventions) {{ groupConvention(builder); }} }} // Any metadata inferred directly inferred by RDF or indirectly inferred via IEndpoint(Parameter)MetadataProviders are // considered less specific than method-level attributes and conventions but more specific than group conventions // so inferred metadata gets added in between these. If group conventions need to override inferred metadata, // they can do so via IEndpointConventionBuilder.Finally like the do to override any other entry-specific metadata. if (isRouteHandler) {{ entry.MetadataPopulator(entry.RouteHandler, builder); }} // Add delegate attributes as metadata before entry-specific conventions but after group conventions. var attributes = handler.Method.GetCustomAttributes(); if (attributes is not null) {{ foreach (var attribute in attributes) {{ builder.Metadata.Add(attribute); }} }} entry.Conventions.IsReadOnly = true; foreach (var entrySpecificConvention in entry.Conventions) {{ entrySpecificConvention(builder); }} // If no convention has modified builder.RequestDelegate, we can use the RequestDelegate returned by the RequestDelegateFactory directly. var conventionOverriddenRequestDelegate = ReferenceEquals(builder.RequestDelegate, redirectRequestDelegate) ? null : builder.RequestDelegate; if (isRouteHandler || builder.FilterFactories.Count > 0) {{ factoryCreatedRequestDelegate = entry.RequestDelegateFactory(entry.RouteHandler, builder); }} Debug.Assert(factoryCreatedRequestDelegate is not null); // Use the overridden RequestDelegate if it exists. If the overridden RequestDelegate is merely wrapping the final RequestDelegate, // it will still work because of the redirectRequestDelegate. builder.RequestDelegate = conventionOverriddenRequestDelegate ?? factoryCreatedRequestDelegate; entry.FinallyConventions.IsReadOnly = true; foreach (var entryFinallyConvention in entry.FinallyConventions) {{ entryFinallyConvention(builder); }} if (groupFinallyConventions is not null) {{ // Group conventions are ordered by the RouteGroupBuilder before // being provided here. foreach (var groupFinallyConvention in groupFinallyConventions) {{ groupFinallyConvention(builder); }} }} return builder; }} private struct RouteEntry {{ public MetadataPopulator MetadataPopulator {{ get; init; }} public RequestDelegateFactoryFunc RequestDelegateFactory {{ get; init; }} public RoutePattern RoutePattern {{ get; init; }} public Delegate RouteHandler {{ get; init; }} public IEnumerable HttpMethods {{ get; init; }} public RouteAttributes RouteAttributes {{ get; init; }} public ThrowOnAddAfterEndpointBuiltConventionCollection Conventions {{ get; init; }} public ThrowOnAddAfterEndpointBuiltConventionCollection FinallyConventions {{ get; init; }} }} [Flags] private enum RouteAttributes {{ // The endpoint was defined by a RequestDelegate, RequestDelegateFactory.Create() should be skipped unless there are endpoint filters. None = 0, // This was added as Delegate route handler, so RequestDelegateFactory.Create() should always be called. RouteHandler = 1, // This was added by MapFallback. Fallback = 2, }} // This private class is only exposed to internal code via ICollection> in RouteEndpointBuilder where only Add is called. private sealed class ThrowOnAddAfterEndpointBuiltConventionCollection : List>, ICollection> {{ // We throw if someone tries to add conventions to the RouteEntry after endpoints have already been resolved meaning the conventions // will not be observed given RouteEndpointDataSource is not meant to be dynamic and uses NullChangeToken.Singleton. public bool IsReadOnly {{ get; set; }} void ICollection>.Add(Action convention) {{ if (IsReadOnly) {{ throw new InvalidOperationException(""Resources.RouteEndpointDataSource_ConventionsCannotBeModifiedAfterBuild""); }} Add(convention); }} }} private class ConventionBuilder : IEndpointConventionBuilder {{ private readonly ICollection> _conventions; private readonly ICollection> _finallyConventions; public ConventionBuilder(ICollection> conventions, ICollection> finallyConventions) {{ _conventions = conventions; _finallyConventions = finallyConventions; }} /// /// Adds the specified convention to the builder. Conventions are used to customize instances. /// /// The convention to add to the builder. public void Add(Action convention) {{ _conventions.Add(convention); }} public void Finally(Action finalConvention) {{ _finallyConventions.Add(finalConvention); }} }} }} }} #endif "; if (sb.Length > 0) { context.AddSource($"RouteBuilderExtensions.g.cs", SourceText.From(mapActionsText, Encoding.UTF8)); } } public void Initialize(GeneratorInitializationContext context) { context.RegisterForSyntaxNotifications(() => new SyntaxReceiver()); } private class SyntaxReceiver : ISyntaxReceiver { private static readonly string[] KnownMethods = new[] { "MapGet", "MapPost", "MapPut", "MapDelete", "MapPatch", "Map", "MapFallback", // This doesn't work yet because it doesn't have a path }; public List MapActions { get; } = new(); public void OnVisitSyntaxNode(SyntaxNode syntaxNode) { if (syntaxNode is InvocationExpressionSyntax { Expression: MemberAccessExpressionSyntax { Name: IdentifierNameSyntax { Identifier: { ValueText: var method } } }, ArgumentList: { Arguments: { Count: 2 } args } } mapActionCall && KnownMethods.Contains(method)) { MapActions.Add(mapActionCall); } } } } class Diagnostics { public static readonly DiagnosticDescriptor UnknownDelegateType = new DiagnosticDescriptor("MIN001", "DelegateTypeUnknown", "Unable to determine the parameter and return types from expression \"{0}\", only method groups, lambda expressions or readonly fields/variables are allowed", "Usage", DiagnosticSeverity.Error, isEnabledByDefault: true); public static readonly DiagnosticDescriptor UnableToResolveParameter = new DiagnosticDescriptor("MIN002", "ParameterSourceUnknown", "Unable to resolve \"{0}\", consider adding [FromXX] attributes to disambiguate the parameter source", "Usage", DiagnosticSeverity.Error, isEnabledByDefault: true); public static readonly DiagnosticDescriptor UnableToResolveTryParseForType = new DiagnosticDescriptor("MIN003", "MissingTryParseForType", "Unable to find a static {0}.TryParse(string, out {0}) implementation", "Usage", DiagnosticSeverity.Error, isEnabledByDefault: true); public static readonly DiagnosticDescriptor MultipleParametersConsumingBody = new DiagnosticDescriptor("MIN005", "MultipleParametersFromBody", "Detecting multiple parameters that attempt to read from the body, consider adding [FromXX] attributes to disambiguate the parameter source", "Usage", DiagnosticSeverity.Error, isEnabledByDefault: true); public static readonly DiagnosticDescriptor AnonymousTypesAsParametersAreNotSupported = new DiagnosticDescriptor("MIN006", "AnonymousTypesAsParametersAreNotSupported", "Anonymous types are not supported as parameters", "Usage", DiagnosticSeverity.Error, isEnabledByDefault: true); } } ================================================ FILE: test/uController.SourceGenerator.Tests/IntegrationTests.cs ================================================ using System.Globalization; using System.Net; using System.Net.Sockets; using System.Numerics; using System.Text.Json; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Http.Metadata; using Microsoft.AspNetCore.Mvc; using Microsoft.CodeAnalysis.Emit; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Microsoft.Extensions.Primitives; using MinimalApis.Extensions.Binding; using Moq; using JsonOptions = Microsoft.AspNetCore.Http.Json.JsonOptions; namespace uController.SourceGenerator.Tests; // TODO: Migrate all tests from https://github.com/dotnet/aspnetcore/blob/main/src/Http/Http.Extensions/test/RequestDelegateFactoryTests.cs // This is a subset. public class IntegrationTests { [Fact] public async Task MapGet_NoParameters_StringReturn() { // Arrange var source = @" app.MapGet(""/"", () => ""Hello world!""); "; // Act var (results, compilation) = await RunGenerator(source); // Assert Assert.Empty(results.Diagnostics); var builderFunc = CreateInvocationFromCompilation(compilation); var builder = CreateEndpointBuilder(); _ = builderFunc(builder); var dataSource = Assert.Single(builder.DataSources); var endpoint = Assert.Single(dataSource.Endpoints); var sourceKeyMetadata = endpoint.Metadata.GetMetadata(); Assert.NotNull(sourceKeyMetadata); var methodMetadata = endpoint.Metadata.GetMetadata(); Assert.NotNull(methodMetadata); var method = Assert.Single(methodMetadata!.HttpMethods); Assert.Equal("GET", method); await AssertEndpointBehavior(endpoint, "Hello world!", 200); } [Fact] public async Task MapGet_StringRouteParameters_StringReturn() { // Arrange var source = @" app.MapGet(""/hello/{name}"", (string name) => $""Hello {name}!""); "; // Act var (results, compilation) = await RunGenerator(source); // Assert Assert.Empty(results.Diagnostics); var builderFunc = CreateInvocationFromCompilation(compilation); var builder = CreateEndpointBuilder(); _ = builderFunc(builder); var dataSource = Assert.Single(builder.DataSources); var endpoint = Assert.Single(dataSource.Endpoints); var sourceKeyMetadata = endpoint.Metadata.GetMetadata(); Assert.NotNull(sourceKeyMetadata); var methodMetadata = endpoint.Metadata.GetMetadata(); Assert.NotNull(methodMetadata); var method = Assert.Single(methodMetadata!.HttpMethods); Assert.Equal("GET", method); await AssertEndpointBehavior( endpoint, "Hello Tester!", 200, routeValues: new(new[] { new KeyValuePair("name", "Tester") })); } [Fact] public async Task MapGet_StringQueryParameters_StringReturn() { // Arrange var source = @" app.MapGet(""/hello"", (string name) => $""Hello {name}!""); "; // Act var (results, compilation) = await RunGenerator(source); // Assert Assert.Empty(results.Diagnostics); var builderFunc = CreateInvocationFromCompilation(compilation); var builder = CreateEndpointBuilder(); _ = builderFunc(builder); var dataSource = Assert.Single(builder.DataSources); var endpoint = Assert.Single(dataSource.Endpoints); var sourceKeyMetadata = endpoint.Metadata.GetMetadata(); Assert.NotNull(sourceKeyMetadata); var methodMetadata = endpoint.Metadata.GetMetadata(); Assert.NotNull(methodMetadata); var method = Assert.Single(methodMetadata!.HttpMethods); Assert.Equal("GET", method); await AssertEndpointBehavior( endpoint, "Hello David!", 200, query: QueryString.Create("name", "David")); } [Fact] public async Task MapGet_ImplicitFromService() { // Arrange var source = $@" app.MapGet(""/"", ({typeof(TodoService)} todo) => todo.ToString()); "; // Act var (results, compilation) = await RunGenerator(source); // Assert Assert.Empty(results.Diagnostics); var builderFunc = CreateInvocationFromCompilation(compilation); var builder = new DefaultEndpointRouteBuilder(new ApplicationBuilder(new ServiceCollection().AddSingleton().BuildServiceProvider())); _ = builderFunc(builder); var dataSource = Assert.Single(builder.DataSources); var endpoint = Assert.Single(dataSource.Endpoints); var sourceKeyMetadata = endpoint.Metadata.GetMetadata(); Assert.NotNull(sourceKeyMetadata); await AssertEndpointBehavior(endpoint, typeof(TodoService).ToString(), 200, builder.ServiceProvider); } [Fact] public async Task MapGetWithNamedFromRouteParameter_UsesFromRouteName() { // Arrange var source = $@" app.MapGet(""/{{value}}"", ([FromRoute(Name = ""value"")] int id, HttpContext httpContext) => {{ httpContext.Items[""value""] = id; }}); "; // Act var (results, compilation) = await RunGenerator(source); // Assert Assert.Empty(results.Diagnostics); var builderFunc = CreateInvocationFromCompilation(compilation); var builder = new DefaultEndpointRouteBuilder(new ApplicationBuilder(new EmptyServiceProvider())); _ = builderFunc(builder); var dataSource = Assert.Single(builder.DataSources); // Trigger Endpoint build by calling getter. var endpoint = Assert.Single(dataSource.Endpoints); // Assert that we don't fallback to the query string var httpContext = new DefaultHttpContext(); httpContext.Request.RouteValues["value"] = "42"; await endpoint.RequestDelegate!(httpContext); Assert.Equal(42, httpContext.Items["value"]); } public static IEnumerable NoResult { get { var testAction = """ void TestAction(HttpContext httpContext) { httpContext.Items.Add("invoked", true); } app.MapGet("/", TestAction); """; // This binds to the RequestDelegate overload //var taskTestAction = """ //Task TaskTestAction(HttpContext httpContext) //{ // httpContext.Items.Add("invoked", true); // return Task.CompletedTask; //} //app.MapGet("/", TaskTestAction); //"""; var valueTaskTestAction = """ ValueTask ValueTaskTestAction(HttpContext httpContext) { httpContext.Items.Add("invoked", true); return ValueTask.CompletedTask; } app.MapGet("/", ValueTaskTestAction); """; var staticTestAction = """ void StaticTestAction(HttpContext httpContext) { httpContext.Items.Add("invoked", true); } app.MapGet("/", StaticTestAction); """; // This binds to the RequestDelegate overload //var staticTaskTestAction = """ //Task StaticTaskTestAction(HttpContext httpContext) //{ // httpContext.Items.Add("invoked", true); // return Task.CompletedTask; //} //app.MapGet("/", StaticTaskTestAction); //"""; var staticValueTaskTestAction = """ ValueTask StaticValueTaskTestAction(HttpContext httpContext) { httpContext.Items.Add("invoked", true); return ValueTask.CompletedTask; } app.MapGet("/", StaticValueTaskTestAction); """; return new List { new object[] { testAction }, // new object[] { taskTestAction }, new object[] { valueTaskTestAction }, new object[] { staticTestAction }, // new object[] { staticTaskTestAction }, new object[] { staticValueTaskTestAction }, }; } } [Theory] [MemberData(nameof(NoResult))] public async Task RequestDelegateInvokesAction(string source) { var requestDelegate = await GetRequestDelegate(source); var httpContext = new DefaultHttpContext(); await requestDelegate(httpContext); Assert.True(httpContext.Items["invoked"] as bool?); } [Fact] public async Task RequestDelegatePopulatesFromRouteParameterBasedOnParameterName() { const string paramName = "value"; const int originalRouteParam = 42; var requestDelegate = await GetRequestDelegate( """ static void TestAction(HttpContext httpContext, [FromRoute] int value) { httpContext.Items.Add("input", value); } app.MapGet("/", TestAction); """); var httpContext = new DefaultHttpContext(); httpContext.Request.RouteValues[paramName] = originalRouteParam.ToString(NumberFormatInfo.InvariantInfo); await requestDelegate(httpContext); Assert.Equal(originalRouteParam, httpContext.Items["input"]); } [Fact] public async Task SpecifiedRouteParametersDoNotFallbackToQueryString() { var requestDelegate = await GetRequestDelegate( """ app.MapGet("/{id}", (int? id, HttpContext httpContext) => { if (id is not null) { httpContext.Items["input"] = id; } }); """); var httpContext = new DefaultHttpContext(); httpContext.Request.Query = new QueryCollection(new Dictionary { ["id"] = "42" }); await requestDelegate(httpContext); Assert.Null(httpContext.Items["input"]); } [Fact] public async Task SpecifiedQueryParametersDoNotFallbackToRouteValues() { var requestDelegate = await GetRequestDelegate( """ app.MapGet("/", (int? id, HttpContext httpContext) => { if (id is not null) { httpContext.Items["input"] = id; } }); """); var httpContext = new DefaultHttpContext(); httpContext.Request.Query = new QueryCollection(new Dictionary { ["id"] = "41" }); httpContext.Request.RouteValues = new() { ["id"] = "42" }; await requestDelegate(httpContext); Assert.Equal(41, httpContext.Items["input"]); } [Fact] public async Task RequestDelegatePopulatesFromRouteOptionalParameter() { var requestDelegate = await GetRequestDelegate( """ static void TestOptional(HttpContext httpContext, [FromRoute] int value = 42) { httpContext.Items.Add("input", value); } app.MapGet("/", TestOptional); """); var httpContext = new DefaultHttpContext(); await requestDelegate(httpContext); Assert.Equal(42, httpContext.Items["input"]); } [Fact] public async Task RequestDelegatePopulatesFromNullableOptionalParameter() { var requestDelegate = await GetRequestDelegate( """ static void TestOptional(HttpContext httpContext, [FromRoute] int? value = 42) { httpContext.Items.Add("input", value); } app.MapGet("/", TestOptional); """); var httpContext = new DefaultHttpContext(); await requestDelegate(httpContext); Assert.Equal(42, httpContext.Items["input"]); } [Fact] public async Task RequestDelegatePopulatesFromOptionalStringParameter() { var requestDelegate = await GetRequestDelegate( """ static void TestOptionalString(HttpContext httpContext, string value = "default") { httpContext.Items.Add("input", value); } app.MapGet("/", TestOptionalString); """); var httpContext = new DefaultHttpContext(); await requestDelegate(httpContext); Assert.Equal("default", httpContext.Items["input"]); } [Fact] public async Task Returns400IfNoMatchingRouteValueForRequiredParam() { const string unmatchedName = "value"; const int unmatchedRouteParam = 42; var requestDelegate = await GetRequestDelegate( """ void TestAction([FromRoute] int foo, HttpContext httpContext) { httpContext.Items.Add("deserializedRouteParam", foo); } app.MapGet("/", TestAction); """); var httpContext = new DefaultHttpContext(); httpContext.Request.RouteValues[unmatchedName] = unmatchedRouteParam.ToString(NumberFormatInfo.InvariantInfo); await requestDelegate(httpContext); Assert.Equal(400, httpContext.Response.StatusCode); Assert.Null(httpContext.Items["deserializedRouteParam"]); } [Fact] public async Task RequestDelegatePrefersBindAsyncOverTryParse() { var requestDelegate = await GetRequestDelegate( $$""" app.MapGet("/", (HttpContext httpContext, {{typeof(MyBindAsyncRecord)}} myBindAsyncRecord) => { httpContext.Items["myBindAsyncRecord"] = myBindAsyncRecord; }); """); var httpContext = new DefaultHttpContext(); httpContext.Request.Headers.Referer = "https://example.org"; await requestDelegate(httpContext); Assert.Equal(new MyBindAsyncRecord(new Uri("https://example.org")), httpContext.Items["myBindAsyncRecord"]); } [Fact] public async Task RequestDelegatePopulatesFromHeaderParameterBasedOnParameterName() { const string customHeaderName = "X-Custom-Header"; const int originalHeaderParam = 42; var requestDelegate = await GetRequestDelegate( $$""" void TestAction(HttpContext httpContext, [FromHeader(Name = "{{customHeaderName}}")] int value) { httpContext.Items["deserializedRouteParam"] = value; } app.MapGet("/", TestAction); """); var httpContext = new DefaultHttpContext(); httpContext.Request.Headers[customHeaderName] = originalHeaderParam.ToString(NumberFormatInfo.InvariantInfo); await requestDelegate(httpContext); Assert.Equal(originalHeaderParam, httpContext.Items["deserializedRouteParam"]); } public static object[][] ImplicitFromBodyActions(bool withAcceptsMetadata = false) { var testImpliedFromBody = $$""" void TestImpliedFromBody(HttpContext httpContext, {{typeof(Todo)}} todo) { httpContext.Items.Add("body", todo); } app.MapPost("/", TestImpliedFromBody); """; var testImpliedFromBodyInterface = $$""" void TestImpliedFromBodyInterface(HttpContext httpContext, {{typeof(ITodo)}} todo) { httpContext.Items.Add("body", todo); } app.MapPost("/", TestImpliedFromBodyInterface); """; var testImpliedFromBodyStruct = $$""" void TestImpliedFromBodyStruct(HttpContext httpContext, {{typeof(TodoStruct)}} todo) { httpContext.Items.Add("body", todo); } app.MapPost("/", TestImpliedFromBodyStruct); """; //void TestImpliedFromBodyStruct_ParameterList([AsParameters] ParametersListWithImplictFromBody args) //{ // args.HttpContext.Items.Add("body", args.Todo); //} if (withAcceptsMetadata) { return new[] { new object[] { testImpliedFromBody, typeof(Todo), new[] { "application/json" } }, new object[] { testImpliedFromBodyInterface, typeof(ITodo), new[] { "application/json" } }, new object[] { testImpliedFromBodyStruct, typeof(TodoStruct), new[] { "application/json" } } // new object[] { (Action)TestImpliedFromBodyStruct_ParameterList }, }; } return new[] { new object[] { testImpliedFromBody }, new object[] { testImpliedFromBodyInterface }, new object[] { testImpliedFromBodyStruct } // new object[] { (Action)TestImpliedFromBodyStruct_ParameterList }, }; } public static object[][] ExplicitFromBodyActions(bool withAcceptsMetadata = false) { var TestExplicitFromBody = $$""" void TestExplicitFromBody(HttpContext httpContext, [FromBody] {{typeof(Todo)}} todo) { httpContext.Items.Add("body", todo); } app.MapPost("/", TestExplicitFromBody); """; // TBD //void TestExplicitFromBody_ParameterList([AsParameters] ParametersListWithExplictFromBody args) //{ // args.HttpContext.Items.Add("body", args.Todo); //} if (withAcceptsMetadata) { return new[] { new object[] { TestExplicitFromBody, typeof(Todo), new[] { "application/json" } }, // new object[] { (Action)TestExplicitFromBody_ParameterList }, }; } return new[] { new object[] { TestExplicitFromBody }, // new object[] { (Action)TestExplicitFromBody_ParameterList }, }; } public static object[][] FromBodyActions { get { return ExplicitFromBodyActions().Concat(ImplicitFromBodyActions()).ToArray(); } } [Theory] [MemberData(nameof(FromBodyActions))] public async Task RequestDelegatePopulatesFromBodyParameter(string source) { RequestDelegate requestDelegate = await GetRequestDelegate(source); Todo originalTodo = new() { Name = "Write more tests!" }; var httpContext = new DefaultHttpContext(); var requestBodyBytes = JsonSerializer.SerializeToUtf8Bytes(originalTodo); var stream = new MemoryStream(requestBodyBytes); httpContext.Request.Body = stream; httpContext.Request.Headers["Content-Type"] = "application/json"; httpContext.Request.Headers["Content-Length"] = stream.Length.ToString(CultureInfo.InvariantCulture); httpContext.Features.Set(new RequestBodyDetectionFeature(true)); var jsonOptions = new JsonOptions(); jsonOptions.SerializerOptions.Converters.Add(new TodoJsonConverter()); var mock = new Mock(); mock.Setup(m => m.GetService(It.IsAny())).Returns(t => { if (t == typeof(IOptions)) { return Options.Create(jsonOptions); } return null; }); httpContext.RequestServices = mock.Object; await requestDelegate(httpContext); var deserializedRequestBody = httpContext.Items["body"]; Assert.NotNull(deserializedRequestBody); Assert.Equal(originalTodo.Name, ((ITodo)deserializedRequestBody!).Name); } public static object?[][] TryParsableParameters { get { var now = DateTime.Now; var types = new List<(Type, object, object)> { (typeof(string) , "plain string", "plain string" ), (typeof(int) , "-42", -42 ), (typeof(int?) , "42", 42), (typeof(uint) , "42", 42U ), (typeof(bool) , "true", true ), (typeof(short) , "-42", (short)-42 ), (typeof(ushort) , "42", (ushort)42 ), (typeof(long) , "-42", -42L ), (typeof(ulong) , "42", 42UL ), (typeof(IntPtr) , "-42", new IntPtr(-42) ), (typeof(char) , "A", 'A' ), (typeof(double) , "0.5", 0.5 ), (typeof(float) , "0.5", 0.5f ), (typeof(Half) , "0.5", (Half)0.5f ), (typeof(decimal) , "0.5", 0.5m ), // TBD // (typeof(Uri) , "https://example.org", new Uri("https://example.org") ), // (typeof(DateTime) , now.ToString("o"), now.ToUniversalTime() ), (typeof(DateTimeOffset) , "1970-01-01T00:00:00.0000000+00:00", DateTimeOffset.UnixEpoch ), (typeof(TimeSpan) , "00:00:42", TimeSpan.FromSeconds(42) ), (typeof(Guid) , "00000000-0000-0000-0000-000000000000", Guid.Empty ), (typeof(Version) , "6.0.0.42", new Version("6.0.0.42") ), (typeof(BigInteger) , "-42", new BigInteger(-42) ), (typeof(IPAddress) , "127.0.0.1", IPAddress.Loopback ), (typeof(IPEndPoint) , "127.0.0.1:80", new IPEndPoint(IPAddress.Loopback, 80) ), (typeof(AddressFamily) , "Unix", AddressFamily.Unix ), }; // TBD //new object[] { (Action)Store, "Nop", ILOpCode.Nop }, //new object[] { (Action)Store, "PublicKey,Retargetable", AssemblyFlags.PublicKey | AssemblyFlags.Retargetable }, //new object[] { (Action)Store, "42", 42 }, //new object[] { (Action)Store, "ValueB", MyEnum.ValueB }, //new object[] { (Action)Store, "https://example.org", new MyTryParseRecord(new Uri("https://example.org")) }, //new object?[] { (Action)Store, null, null }, static Type? Unwrap(Type type) { if (type.IsGenericType && !type.IsGenericTypeDefinition) { // instantiated generic type only Type genericType = type.GetGenericTypeDefinition(); if (genericType.Equals(typeof(Nullable<>))) { return type.GetGenericArguments()[0]; } } return null; } var results = new List(); foreach (var (type, val, expected) in types) { var source = $$""" static void Store(HttpContext httpContext, {{(Unwrap(type) is Type t ? $"{t}?" : $"{type}")}} tryParsable) { httpContext.Items["tryParsable"] = tryParsable; } app.MapGet("/{tryParsable}", Store); """; results.Add(new[] { source, val, expected }); } return results.ToArray(); } } [Theory] [MemberData(nameof(TryParsableParameters))] public async Task RequestDelegatePopulatesUnattributedTryParsableParametersFromRouteValue(string source, string? routeValue, object? expectedParameterValue) { var requestDelegate = await GetRequestDelegate(source); var httpContext = new DefaultHttpContext(); httpContext.Request.RouteValues["tryParsable"] = routeValue; await requestDelegate(httpContext); Assert.Equal(expectedParameterValue, httpContext.Items["tryParsable"]); } public static object[][] ExplicitFromServiceActions { get { var testExplicitFromService = $$""" void TestExplicitFromService(HttpContext httpContext, [{{typeof(FromServiceAttribute)}}] {{typeof(MyService)}} myService) { httpContext.Items.Add("service", myService); } app.MapGet("/", TestExplicitFromService); """; // TBD //void TestExplicitFromService_FromParameterList([AsParameters] ParametersListWithExplictFromService args) //{ // args.HttpContext.Items.Add("service", args.MyService); //} var testExplicitFromIEnumerableService = $$""" void TestExplicitFromIEnumerableService(HttpContext httpContext, [{{typeof(FromServiceAttribute)}}] IEnumerable<{{typeof(MyService)}}> myServices) { httpContext.Items.Add("service", myServices.Single()); } app.MapGet("/", TestExplicitFromIEnumerableService); """; var testExplictMultipleFromService = $$""" void TestExplicitMultipleFromService(HttpContext httpContext, [{{typeof(FromServiceAttribute)}}] {{typeof(MyService)}} myService, [{{typeof(FromServiceAttribute)}}] IEnumerable<{{typeof(MyService)}}> myServices) { httpContext.Items.Add("service", myService); } app.MapGet("/", TestExplicitMultipleFromService); """; return new object[][] { new[] { testExplicitFromService }, // TBD // new object[] { (Action)TestExplicitFromService_FromParameterList }, new[] { testExplicitFromIEnumerableService }, new[] { testExplictMultipleFromService }, }; } } public static object[][] ImplicitFromServiceActions { get { var testImpliedFromService = $$""" void TestImpliedFromService(HttpContext httpContext, {{typeof(IMyService)}} myService) { httpContext.Items.Add("service", myService); } app.MapGet("/", TestImpliedFromService); """; //void TestImpliedFromService_FromParameterList([AsParameters] ParametersListWithImplictFromService args) //{ // args.HttpContext.Items.Add("service", args.MyService); //} var testImpliedIEnumerableFromService = $$""" void TestImpliedIEnumerableFromService(HttpContext httpContext, IEnumerable<{{typeof(MyService)}}> myServices) { httpContext.Items.Add("service", myServices.Single()); } app.MapGet("/", TestImpliedIEnumerableFromService); """; var testImpliedFromServiceBasedOnContainer = $$""" void TestImpliedFromServiceBasedOnContainer(HttpContext httpContext, {{typeof(MyService)}} myService) { httpContext.Items.Add("service", myService); } app.MapGet("/", TestImpliedFromServiceBasedOnContainer); """; return new object[][] { new[] { testImpliedFromService }, // new object[] { (Action)TestImpliedFromService_FromParameterList }, new[] { testImpliedIEnumerableFromService }, new[] { testImpliedFromServiceBasedOnContainer }, }; } } [Theory] [MemberData(nameof(FromServiceActions))] public async Task RequestDelegatePopulatesParametersFromServiceWithAndWithoutAttribute(string source) { var myOriginalService = new MyService(); var serviceCollection = new ServiceCollection(); serviceCollection.AddSingleton(myOriginalService); serviceCollection.AddSingleton(myOriginalService); var services = serviceCollection.BuildServiceProvider(); var requestDelegate = await GetRequestDelegate(source, services); using var requestScoped = services.CreateScope(); var httpContext = new DefaultHttpContext { RequestServices = requestScoped.ServiceProvider }; await requestDelegate(httpContext); Assert.Same(myOriginalService, httpContext.Items["service"]); } public static object[][] FromServiceActions { get { return ImplicitFromServiceActions.Concat(ExplicitFromServiceActions).ToArray(); } } public static object[][] FromFormActions(bool withAcceptsMetadata = false) { var implicitFromFormFile = $$""" app.MapPost("/fileupload", (IFormFile file) => { return $"Uploaded {file.Name}"; }); """; var implicitFromFormCollection = $$""" app.MapPost("/formpost", (IFormCollection formCollection) => { return $"Uploaded {formCollection.Count} files"; }); """; var explicitFromFormFile = $$""" app.MapPost("/fileupload", ([FromForm] IFormFile file) => { return $"Uploaded {file.Name}"; }); """; var explicitFromFormCollection = $$""" app.MapPost("/formpost", ([FromForm] IFormCollection formCollection) => { return $"Uploaded {formCollection.Count} files"; }); """; if (withAcceptsMetadata) { return new[] { new[] { (object)implicitFromFormFile, typeof(IFormFile), new[] { "multipart/form-data" }}, new[] { (object)implicitFromFormCollection, typeof(IFormCollection), new[] { "multipart/form-data" }}, new[] { (object)explicitFromFormFile, typeof(IFormFile), new[] { "multipart/form-data" }}, new[] { (object)explicitFromFormCollection, typeof(IFormCollection), new[] { "multipart/form-data" }} }; } return new[] { new[] { (object)implicitFromFormFile }, new[] { (object)implicitFromFormCollection }, new[] { (object)explicitFromFormFile }, new[] { (object)explicitFromFormCollection } }; } [Theory] [MemberData(nameof(ImplicitFromBodyActions), parameters: new object[] { true })] [MemberData(nameof(ExplicitFromBodyActions), parameters: new object[] { true })] [MemberData(nameof(FromFormActions), parameters: new object[] { true })] public async Task PopulatesAcceptsMetadataForRequestBody(string source, Type expectedType, string[] expectedContentTypes) { var endpoint = await GetEndpoint(source); var acceptsMetadata = endpoint.Metadata.GetMetadata(); Assert.NotNull(acceptsMetadata); Assert.Equal(expectedType, acceptsMetadata.RequestType); Assert.Equal(expectedContentTypes, acceptsMetadata.ContentTypes); } [Theory] [MemberData(nameof(FromServiceActions))] public async Task DoesNotPopulateAcceptsMetadataForServices(string source) { var myOriginalService = new MyService(); var serviceProvider = new ServiceCollection() .AddSingleton(myOriginalService) .AddSingleton(myOriginalService) .BuildServiceProvider(); var endpoint = await GetEndpoint(source, serviceProvider); var acceptsMetadata = endpoint.Metadata.GetMetadata(); Assert.Null(acceptsMetadata); } [Fact] public async Task SupportsNullableReferenceTypesInParameters() { var source = """ app.MapGet("/", (string? nullableString, DateTime? nullableDateTime) => $"{nullableString} {nullableDateTime}"); """; var endpoint = await GetEndpoint(source); } public static object?[][] FromQueryOptionality { get { var requiredQueryParam = """app.MapGet("/", (string name) => $"Hello {name}!");"""; var defaultValueQueryParam = """ string defaultValueQueryParam(string name = "DefaultName") => $"Hello {name}!"; app.MapGet("/", defaultValueQueryParam); """; var nullableQueryParam = """app.MapGet("/", (string? name) => $"Hello {name}!");"""; var requiredParseableQueryParam = """app.MapGet("/", (int age) => $"Age: {age}");"""; var defaultValueParseableQueryParam = """ string defaultValuePareseableQueryParam(int age = 12) => $"Age: {age}"; app.MapGet("/", defaultValuePareseableQueryParam); """; var nullableQueryParseableParam = """app.MapGet("/", (int? age) => $"Age: {age}");"""; return new[] { new object?[] { requiredQueryParam, "name", null, 400, null}, new object?[] { requiredQueryParam, "name", "TestName", 200, "Hello TestName!" }, new object?[] { defaultValueQueryParam, "name", null, 200, "Hello DefaultName!" }, new object?[] { defaultValueQueryParam, "name", "TestName", 200, "Hello TestName!" }, new object?[] { nullableQueryParam, "name", null, 200, "Hello !" }, new object?[] { nullableQueryParam, "name", "TestName", 200, "Hello TestName!"}, new object?[] { requiredParseableQueryParam, "age", null, 400, null}, new object?[] { requiredParseableQueryParam, "age", "42", 200, "Age: 42" }, new object?[] { defaultValueParseableQueryParam, "age", null, 200, "Age: 12" }, new object?[] { defaultValueParseableQueryParam, "age", "42", 200, "Age: 42" }, new object?[] { nullableQueryParseableParam, "age", null, 200, "Age: " }, new object?[] { nullableQueryParseableParam, "age", "42", 200, "Age: 42"}, }; } } [Theory] [MemberData(nameof(FromQueryOptionality))] public async Task HandlesQueryParamOptionality(string source, string paramName, string? queryParam, int expectedStatusCode, string? expectedResponse) { var endpoint = await GetEndpoint(source); QueryString? query = queryParam is not null ? QueryString.Create(paramName, queryParam) : null; await AssertEndpointBehavior( endpoint, expectedResponse ?? string.Empty, expectedStatusCode, query: query); } public static object?[][] FromRouteOptionality { get { var requiredRouteParam = """app.MapGet("/{name}", (string name) => $"Hello {name}!");"""; var defaultValueRouteParam = """ string defaultValueQueryParam(string name = "DefaultName") => $"Hello {name}!"; app.MapGet("/{name}", defaultValueQueryParam); """; var nullableRouteParam = """app.MapGet("/{name}", (string? name) => $"Hello {name}!");"""; var requiredParseableRouteParam = """app.MapGet("/{age}", (int age) => $"Age: {age}");"""; var defaultValueParseableRouteParam = """ string defaultValuePareseableRouteParam(int age = 12) => $"Age: {age}"; app.MapGet("/{age}", defaultValuePareseableRouteParam); """; var nullableQueryParseableParam = """app.MapGet("/{age}", (int? age) => $"Age: {age}");"""; return new[] { new object?[] { requiredRouteParam, "name", null, 400, null}, new object?[] { requiredRouteParam, "name", "TestName", 200, "Hello TestName!" }, new object?[] { defaultValueRouteParam, "name", null, 200, "Hello DefaultName!" }, new object?[] { defaultValueRouteParam, "name", "TestName", 200, "Hello TestName!" }, new object?[] { nullableRouteParam, "name", null, 200, "Hello !" }, new object?[] { nullableRouteParam, "name", "TestName", 200, "Hello TestName!"}, new object?[] { requiredParseableRouteParam, "age", null, 400, null}, new object?[] { requiredParseableRouteParam, "age", "42", 200, "Age: 42" }, new object?[] { defaultValueParseableRouteParam, "age", null, 200, "Age: 12" }, new object?[] { defaultValueParseableRouteParam, "age", "42", 200, "Age: 42" }, new object?[] { nullableQueryParseableParam, "age", null, 200, "Age: " }, new object?[] { nullableQueryParseableParam, "age", "42", 200, "Age: 42"}, }; } } [Theory] [MemberData(nameof(FromRouteOptionality))] public async Task HandlesRouteParamOptionality(string source, string paramName, string? routeParam, int expectedStatusCode, string? expectedResponse) { var endpoint = await GetEndpoint(source); var routeValue = routeParam is not null ? new RouteValueDictionary { { paramName, routeParam } } : null; await AssertEndpointBehavior( endpoint, expectedResponse ?? string.Empty, expectedStatusCode, routeValues: routeValue); } public static object?[][] FromBodyOptionality { get { var requiredBodyParam = $""" app.MapPost("/todo", ({typeof(Todo)} todo) => todo); """; var defaultValueBodyParam = $""" {typeof(Todo)}? getTodo({typeof(Todo)}? todo = default) => todo; app.MapPost("/todo", getTodo); """; var nullableBodyParam = $""" app.MapPost("/todo-1", ({typeof(Todo)}? todo) => todo); """; var disallowEmptyAndNonOptional = $""" app.MapPost("/todo-2", ([{typeof(FromBodyAttribute)}(AllowEmpty = false)] {typeof(Todo)} todo) => todo); """; var allowEmptyAndNonOptional = $""" app.MapPost("/todo-3", ([{typeof(FromBodyAttribute)}(AllowEmpty = true)] {typeof(Todo)} todo) => todo); """; var allowEmptyAndOptional = $""" app.MapPost("/todo-4", ([{typeof(FromBodyAttribute)}(AllowEmpty = true)] {typeof(Todo)}? todo) => todo); """; var disallowEmptyAndOptional = $""" app.MapPost("/todo-5", ([{typeof(FromBodyAttribute)}(AllowEmpty = false)] {typeof(Todo)}? todo) => todo); """; var todo = new Todo { Name = "Run tests" }; return new[] { new object?[] { requiredBodyParam, null, 400 }, new object?[] { requiredBodyParam, todo, 200 }, new object?[] { defaultValueBodyParam, null, 200 }, new object?[] { defaultValueBodyParam, todo, 200 }, new object?[] { nullableBodyParam, null, 200 }, new object?[] { nullableBodyParam, todo, 200 }, new object?[] { disallowEmptyAndNonOptional, null, 400 }, new object?[] { allowEmptyAndNonOptional, null, 200 }, new object?[] { allowEmptyAndOptional, null, 200 }, new object?[] { disallowEmptyAndOptional, null, 200 } }; } } [Theory] [MemberData(nameof(FromBodyOptionality))] public async Task HandlesBodyParamOptionality(string source, Todo? bodyParam, int expectedStatusCode) { var requestDelegate = await GetRequestDelegate(source); var httpContext = new DefaultHttpContext(); var outStream = new MemoryStream(); httpContext.Response.Body = outStream; var requestBodyBytes = JsonSerializer.SerializeToUtf8Bytes(bodyParam); var stream = new MemoryStream(requestBodyBytes); httpContext.Request.Body = stream; httpContext.Request.Headers["Content-Type"] = "application/json"; httpContext.Request.Headers["Content-Length"] = stream.Length.ToString(CultureInfo.InvariantCulture); httpContext.Features.Set(new RequestBodyDetectionFeature(true)); var jsonOptions = new JsonOptions(); jsonOptions.SerializerOptions.Converters.Add(new TodoJsonConverter()); var mock = new Mock(); mock.Setup(m => m.GetService(It.IsAny())).Returns(t => { if (t == typeof(IOptions)) { return Options.Create(jsonOptions); } return null; }); httpContext.RequestServices = mock.Object; await requestDelegate(httpContext); Assert.Equal(expectedStatusCode, httpContext.Response.StatusCode); if (expectedStatusCode == 200) { var httpResponse = httpContext.Response; httpResponse.Body.Seek(0, SeekOrigin.Begin); var streamReader = new StreamReader(httpResponse.Body); var body = await streamReader.ReadToEndAsync(); Assert.Equal(JsonSerializer.Serialize(bodyParam, options: new JsonSerializerOptions(JsonSerializerDefaults.Web)), body); } } public static object?[][] FromServiceOptionality { get { var requiredExplicitService = $""" void requiredExplicitService([{typeof(FromServiceAttribute)}]{typeof(MyService)} service, HttpContext httpContext) => httpContext.Items.Add("service", service); app.MapGet("/", requiredExplicitService); """; var defaultValueExplicitServiceParam = $""" void defaultValueExplicitServiceParam(HttpContext httpContext, [{typeof(FromServiceAttribute)}]{typeof(MyService)}? service = null) => httpContext.Items.Add("service", service); app.MapGet("/", defaultValueExplicitServiceParam); """; var nullableExplicitServiceParam = $""" app.MapGet("/", (HttpContext httpContext, [{typeof(FromServiceAttribute)}]{typeof(MyService)}? service) => httpContext.Items.Add("service", service)); """; return new [] { new object?[] { requiredExplicitService, false, false}, new object?[] { requiredExplicitService, true, true}, new object?[] { defaultValueExplicitServiceParam, false, true}, new object?[] { defaultValueExplicitServiceParam, true, true}, new object?[] { nullableExplicitServiceParam, false, true}, new object?[] { nullableExplicitServiceParam, true, true}, }; } } [Theory] [MemberData(nameof(FromServiceOptionality))] public async Task HandleFromServiceOptionality(string source, bool hasService, bool isValid) { var myOriginalService = new MyService(); var serviceCollection = new ServiceCollection(); serviceCollection.AddSingleton(myOriginalService); serviceCollection.AddSingleton(myOriginalService); var services = serviceCollection.BuildServiceProvider(); var requestDelegate = await GetRequestDelegate(source, hasService ? services : null) ; using var requestScoped = services.CreateScope(); var httpContext = new DefaultHttpContext { RequestServices = hasService ? requestScoped.ServiceProvider : new ServiceCollection().BuildServiceProvider() }; if (isValid) { await requestDelegate(httpContext); Assert.Same(hasService ? myOriginalService : null, httpContext.Items["service"]); Assert.Equal(200,httpContext.Response.StatusCode); } else { await Assert.ThrowsAsync(() => requestDelegate(httpContext)); Assert.False(httpContext.RequestAborted.IsCancellationRequested); } } public static IEnumerable BindAsyncOptionality { get { var requiredReferenceType = $""" app.MapPost("/1", (HttpContext context, {typeof(MyBindAsyncRecord)} myBindAsyncRecord) => context.Items["uri"] = myBindAsyncRecord.Uri); """; var defaultReferenceType = $""" void defaultReferenceTypeHandler(HttpContext context, {typeof(MyBindAsyncRecord)}? myBindAsyncRecord = null) => context.Items["uri"] = myBindAsyncRecord?.Uri; app.MapPost("/2", defaultReferenceTypeHandler); """; var nullableReferenceType = $""" app.MapPost("/3", (HttpContext context, {typeof(MyBindAsyncRecord)}? myBindAsyncRecord) => context.Items["uri"] = myBindAsyncRecord?.Uri); """; var requiredReferenceTypeSimple = $""" app.MapPost("/4", (HttpContext context, {typeof(MySimpleBindAsyncRecord)} mySimpleBindAsyncRecord) => context.Items["uri"] = mySimpleBindAsyncRecord.Uri); """; var requiredValueType = $""" app.MapPost("/5", (HttpContext context, {typeof(MyNullableBindAsyncStruct)} myNullableBindAsyncStruct) => context.Items["uri"] = myNullableBindAsyncStruct.Uri); """; var defaultValueType = $""" void defaultValueTypeHandler(HttpContext context, {typeof(MyNullableBindAsyncStruct)}? myNullableBindAsyncStruct = null) => context.Items["uri"] = myNullableBindAsyncStruct?.Uri; app.MapPost("/6", defaultValueTypeHandler); """; var nullableValueType = $""" app.MapPost("/7", (HttpContext context, {typeof(MyNullableBindAsyncStruct)}? myNullableBindAsyncStruct) => context.Items["uri"] = myNullableBindAsyncStruct?.Uri); """; var requiredValueTypeSimple = $""" app.MapPost("/8", (HttpContext context, {typeof(MySimpleBindAsyncStruct)} mySimpleBindAsyncStruct) => context.Items["uri"] = mySimpleBindAsyncStruct.Uri); """; return new object?[][] { new object?[] { requiredReferenceType, false, true, false }, new object?[] { requiredReferenceType, true, false, false, }, new object?[] { requiredReferenceTypeSimple, true, false, false }, new object?[] { defaultReferenceType, false, false, false, }, new object?[] { defaultReferenceType, true, false, false }, new object?[] { nullableReferenceType, false, false, false }, new object?[] { nullableReferenceType, true, false, false }, new object?[] { requiredValueType, false, true, true }, new object?[] { requiredValueType, true, false, true }, new object?[] { requiredValueTypeSimple, true, false, true }, new object?[] { defaultValueType, false, false, true }, new object?[] { defaultValueType, true, false, true }, new object?[] { nullableValueType, false, false, true }, new object?[] { nullableValueType, true, false, true }, }; } } [Theory] [MemberData(nameof(BindAsyncOptionality))] public async Task HandleBindAsyncOptionality(string source, bool includeReferer, bool isInvalid, bool isStruct) { // Arrange var requestDelegate = await GetRequestDelegate(source); var httpContext = new DefaultHttpContext(); if (includeReferer) { httpContext.Request.Headers.Referer = "https://example.org"; } // Assert if (!isInvalid) { await requestDelegate(httpContext); Assert.Equal(200, httpContext.Response.StatusCode); if (includeReferer) { Assert.Equal(new Uri("https://example.org"), httpContext.Items["uri"]); } else { Assert.Null(httpContext.Items["uri"]); } } else { await requestDelegate(httpContext); Assert.Equal(400, httpContext.Response.StatusCode); Assert.False(httpContext.RequestAborted.IsCancellationRequested); } } [Theory] [InlineData("""app.MapGet("/multiple-nn", (Microsoft.Extensions.Primitives.StringValues queries) => queries);""")] [InlineData("""app.MapGet("/multiple-n", (Microsoft.Extensions.Primitives.StringValues? queries) => queries);""")] public async Task HandleQueryHandlerTypeDifferentFromResolved(string source) { var requestDelegate = await GetRequestDelegate(source); var httpContext = new DefaultHttpContext(); await requestDelegate(httpContext); } public async Task GetEndpoint(string source, IServiceProvider? serviceProvider = null) { // Act var (results, compilation) = await RunGenerator(source); // Assert Assert.Empty(results.Diagnostics); var builderFunc = CreateInvocationFromCompilation(compilation); var builder = new DefaultEndpointRouteBuilder(new ApplicationBuilder(serviceProvider ?? new EmptyServiceProvider())); _ = builderFunc(builder); var dataSource = Assert.Single(builder.DataSources); // Trigger Endpoint build by calling getter. var endpoint = Assert.Single(dataSource.Endpoints); var sourceKeyMetadata = endpoint.Metadata.GetMetadata(); Assert.NotNull(sourceKeyMetadata); return endpoint; } private async Task GetRequestDelegate(string source, IServiceProvider? serviceProvider = null) { var endpoint = await GetEndpoint(source, serviceProvider); Assert.NotNull(endpoint.RequestDelegate); return endpoint.RequestDelegate; } private static async Task AssertEndpointBehavior( Endpoint endpoint, string expectedResponse, int expectedStatusCode, IServiceProvider? serviceProvider = null, RouteValueDictionary? routeValues = null, QueryString? query = null) { var httpContext = new DefaultHttpContext(); IServiceScope? scope = null; if (serviceProvider is not null) { scope = serviceProvider.CreateScope(); httpContext.RequestServices = scope.ServiceProvider; } var outStream = new MemoryStream(); httpContext.Response.Body = outStream; if (query is { } q) { httpContext.Request.QueryString = q; } if (routeValues is not null) { httpContext.Request.RouteValues = routeValues; } Assert.NotNull(endpoint.RequestDelegate); await endpoint.RequestDelegate(httpContext); var httpResponse = httpContext.Response; httpResponse.Body.Seek(0, SeekOrigin.Begin); var streamReader = new StreamReader(httpResponse.Body); var body = await streamReader.ReadToEndAsync(); Assert.Equal(expectedStatusCode, httpContext.Response.StatusCode); Assert.Equal(expectedResponse, body); scope?.Dispose(); } private static Func CreateInvocationFromCompilation(Compilation compilation) { var assemblyName = compilation.AssemblyName!; var symbolsName = Path.ChangeExtension(assemblyName, "pdb"); var output = new MemoryStream(); var pdb = new MemoryStream(); var emitOptions = new EmitOptions( debugInformationFormat: DebugInformationFormat.PortablePdb, pdbFilePath: symbolsName); var embeddedTexts = new List(); // Make sure we embed the sources in pdb for easy debugging foreach (var syntaxTree in compilation.SyntaxTrees) { var text = syntaxTree.GetText(); var encoding = text.Encoding ?? Encoding.UTF8; var buffer = encoding.GetBytes(text.ToString()); var sourceText = SourceText.From(buffer, buffer.Length, encoding, canBeEmbedded: true); var syntaxRootNode = (CSharpSyntaxNode)syntaxTree.GetRoot(); var newSyntaxTree = CSharpSyntaxTree.Create(syntaxRootNode, options: null, encoding: encoding, path: syntaxTree.FilePath); compilation = compilation.ReplaceSyntaxTree(syntaxTree, newSyntaxTree); embeddedTexts.Add(EmbeddedText.FromSource(syntaxTree.FilePath, sourceText)); } var result = compilation.Emit(output, pdb, options: emitOptions, embeddedTexts: embeddedTexts); Assert.Empty(result.Diagnostics.Where(d => d.Severity > DiagnosticSeverity.Warning)); Assert.True(result.Success); output.Position = 0; pdb.Position = 0; var assembly = AssemblyLoadContext.Default.LoadFromStream(output, pdb); var handler = assembly?.GetType("TestMapActions") ?.GetMethod("MapTestEndpoints", BindingFlags.Public | BindingFlags.Static) ?.CreateDelegate>(); Assert.NotNull(handler); return handler; } private static async Task<(GeneratorRunResult, Compilation)> RunGenerator(string mapAction) { var project = CreateProject(); var source = $$""" using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Routing; public static class TestMapActions { public static IEndpointRouteBuilder MapTestEndpoints(this IEndpointRouteBuilder app) { {{mapAction}} return app; } } """; project = project.AddDocument("TestMapActions.cs", SourceText.From(source, Encoding.UTF8)).Project; var compilation = await project.GetCompilationAsync(); GeneratorDriver driver = CSharpGeneratorDriver.Create(new[] { new uControllerGenerator() }, parseOptions: (CSharpParseOptions)project.ParseOptions!); Assert.NotNull(compilation); driver = driver.RunGeneratorsAndUpdateCompilation(compilation, out var outputCompilation, out var _); var results = driver.GetRunResult(); var diagnostics = outputCompilation.GetDiagnostics(); Assert.Empty(diagnostics.Where(d => d.Severity > DiagnosticSeverity.Warning)); return (results.Results[0], outputCompilation); } private static Project CreateProject() { var projectName = $"TestProject-{Guid.NewGuid()}"; var projectId = ProjectId.CreateNewId(projectName); var solution = new AdhocWorkspace() .CurrentSolution .AddProject(projectId, projectName, projectName, LanguageNames.CSharp); var project = solution.Projects.Single() .WithCompilationOptions(new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary) .WithNullableContextOptions(NullableContextOptions.Enable)) .WithParseOptions(new CSharpParseOptions(LanguageVersion.CSharp11).WithPreprocessorSymbols("NET7_0_OR_GREATER")); var resolver = new AppLocalResolver(); var dependencyContext = DependencyContext.Load(typeof(IntegrationTests).Assembly); Assert.NotNull(dependencyContext); foreach (var defaultCompileLibrary in dependencyContext.CompileLibraries) { foreach (var resolveReferencePath in defaultCompileLibrary.ResolveReferencePaths(resolver)) { // Skip the source generator itself if (resolveReferencePath.Equals(typeof(uControllerGenerator).Assembly.Location)) { continue; } project = project.AddMetadataReference(MetadataReference.CreateFromFile(resolveReferencePath)); } } return project; } private class RequestBodyDetectionFeature : IHttpRequestBodyDetectionFeature { public RequestBodyDetectionFeature(bool canHaveBody) { CanHaveBody = canHaveBody; } public bool CanHaveBody { get; } } private static IEndpointRouteBuilder CreateEndpointBuilder(IServiceProvider? serviceProvider = null) { return new DefaultEndpointRouteBuilder(new ApplicationBuilder(serviceProvider ?? new EmptyServiceProvider())); } private class AppLocalResolver : ICompilationAssemblyResolver { public bool TryResolveAssemblyPaths(CompilationLibrary library, List? assemblies) { foreach (var assembly in library.Assemblies) { var dll = Path.Combine(Directory.GetCurrentDirectory(), "refs", Path.GetFileName(assembly)); if (File.Exists(dll)) { assemblies ??= new(); assemblies.Add(dll); return true; } dll = Path.Combine(Directory.GetCurrentDirectory(), Path.GetFileName(assembly)); if (File.Exists(dll)) { assemblies ??= new(); assemblies.Add(dll); return true; } } return false; } } private class EmptyServiceProvider : IServiceScope, IServiceProvider, IServiceScopeFactory { public IServiceProvider ServiceProvider => this; public RouteHandlerOptions RouteHandlerOptions { get; set; } = new RouteHandlerOptions(); public IServiceScope CreateScope() { return this; } public void Dispose() { } public object? GetService(Type serviceType) { return null; } } private class DefaultEndpointRouteBuilder : IEndpointRouteBuilder { public DefaultEndpointRouteBuilder(IApplicationBuilder applicationBuilder) { ApplicationBuilder = applicationBuilder ?? throw new ArgumentNullException(nameof(applicationBuilder)); DataSources = new List(); } public IApplicationBuilder ApplicationBuilder { get; } public IApplicationBuilder CreateApplicationBuilder() => ApplicationBuilder.New(); public ICollection DataSources { get; } public IServiceProvider ServiceProvider => ApplicationBuilder.ApplicationServices; } } ================================================ FILE: test/uController.SourceGenerator.Tests/SharedTypes.cs ================================================ using System.Text.Json.Serialization; using System.Text.Json; using Microsoft.AspNetCore.Http.Metadata; namespace uController.SourceGenerator.Tests; // Types shared between the tests and compilation. They *must* be public. public class FromServiceAttribute : Attribute, IFromServiceMetadata { } public class FromBodyAttribute : Attribute, IFromBodyMetadata { public bool AllowEmpty { get; set; } } public interface IMyService { } public class MyService : IMyService { } public class TodoService { } public record MyBindAsyncRecord(Uri Uri) { public static ValueTask BindAsync(HttpContext context, ParameterInfo parameter) { Assert.Equal(typeof(MyBindAsyncRecord), parameter.ParameterType); Assert.StartsWith("myBindAsyncRecord", parameter.Name); if (!Uri.TryCreate(context.Request.Headers.Referer, UriKind.Absolute, out var uri)) { return new(result: null); } return new(result: new(uri)); } // BindAsync(HttpContext, ParameterInfo) should be preferred over TryParse(string, ...) if there's // no [FromRoute] or [FromQuery] attributes. public static bool TryParse(string? value, out MyBindAsyncRecord? result) => throw new NotImplementedException(); } public record MySimpleBindAsyncRecord(Uri Uri) { public static ValueTask BindAsync(HttpContext context) { if (!Uri.TryCreate(context.Request.Headers.Referer, UriKind.Absolute, out var uri)) { return new(result: null); } return new(result: new(uri)); } } public record struct MyNullableBindAsyncStruct(Uri Uri) { public static ValueTask BindAsync(HttpContext context, ParameterInfo parameter) { Assert.True(parameter.ParameterType == typeof(MyNullableBindAsyncStruct) || parameter.ParameterType == typeof(MyNullableBindAsyncStruct?)); Assert.Equal("myNullableBindAsyncStruct", parameter.Name); if (!Uri.TryCreate(context.Request.Headers.Referer, UriKind.Absolute, out var uri)) { return new(result: null); } return new(result: new(uri)); } } public record struct MySimpleBindAsyncStruct(Uri Uri) { public static ValueTask BindAsync(HttpContext context) { if (!Uri.TryCreate(context.Request.Headers.Referer, UriKind.Absolute, out var uri)) { throw new BadHttpRequestException("The request is missing the required Referer header."); } return new(result: new(uri)); } } public interface ITodo { public int Id { get; } public string? Name { get; } public bool IsComplete { get; } } public class Todo : ITodo { public int Id { get; set; } public string? Name { get; set; } = "Todo"; public bool IsComplete { get; set; } } public record struct TodoStruct(int Id, string? Name, bool IsComplete) : ITodo; public class TodoJsonConverter : JsonConverter { public override ITodo? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { var todo = new Todo(); while (reader.Read()) { if (reader.TokenType == JsonTokenType.EndObject) { break; } var property = reader.GetString()!; reader.Read(); switch (property.ToLowerInvariant()) { case "id": todo.Id = reader.GetInt32(); break; case "name": todo.Name = reader.GetString(); break; case "iscomplete": todo.IsComplete = reader.GetBoolean(); break; default: break; } } return todo; } public override void Write(Utf8JsonWriter writer, ITodo value, JsonSerializerOptions options) { throw new NotImplementedException(); } } ================================================ FILE: test/uController.SourceGenerator.Tests/SourceKey.cs ================================================ namespace Microsoft.AspNetCore.Builder { public record SourceKey(string Path, int Line); } ================================================ FILE: test/uController.SourceGenerator.Tests/Usings.cs ================================================ global using System; global using System.Collections.Generic; global using System.IO; global using System.Linq; global using System.Reflection; global using System.Runtime.Loader; global using System.Text; global using System.Threading.Tasks; global using Microsoft.AspNetCore.Builder; global using Microsoft.AspNetCore.Http; global using Microsoft.AspNetCore.Routing; global using Microsoft.CodeAnalysis; global using Microsoft.CodeAnalysis.CSharp; global using Microsoft.CodeAnalysis.Text; global using Microsoft.Extensions.DependencyInjection; global using Microsoft.Extensions.DependencyModel; global using Microsoft.Extensions.DependencyModel.Resolution; global using Xunit; global using Xunit.Abstractions; ================================================ FILE: test/uController.SourceGenerator.Tests/uController.SourceGenerator.Tests.csproj ================================================  net7.0 enable false true runtime; build; native; contentfiles; analyzers; buildtransitive all runtime; build; native; contentfiles; analyzers; buildtransitive all ================================================ FILE: uController.sln ================================================  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.4.32728.343 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sample", "samples\Sample.csproj", "{E75EECDA-E740-454B-BA83-7B7AC0D9E0A9}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "uController.SourceGenerator", "src\uController.SourceGenerator\uController.SourceGenerator.csproj", "{045C64E7-5639-4ECD-BEE3-57597E7CF77E}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{9AC9FBC2-655D-4D1C-B3B0-8429140C1125}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{37EABDC7-EC04-40DB-AADB-73232A885C63}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{F0473E60-E67C-4908-97BE-6F37C6EC9A48}" ProjectSection(SolutionItems) = preProject README.md = README.md EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{23D17AAC-308D-48E4-9F5F-6B60322BFF9A}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "uController.SourceGenerator.Tests", "test\uController.SourceGenerator.Tests\uController.SourceGenerator.Tests.csproj", "{6EB60A4E-87BA-472D-997E-D4C0361A2489}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {E75EECDA-E740-454B-BA83-7B7AC0D9E0A9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {E75EECDA-E740-454B-BA83-7B7AC0D9E0A9}.Debug|Any CPU.Build.0 = Debug|Any CPU {E75EECDA-E740-454B-BA83-7B7AC0D9E0A9}.Release|Any CPU.ActiveCfg = Release|Any CPU {E75EECDA-E740-454B-BA83-7B7AC0D9E0A9}.Release|Any CPU.Build.0 = Release|Any CPU {045C64E7-5639-4ECD-BEE3-57597E7CF77E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {045C64E7-5639-4ECD-BEE3-57597E7CF77E}.Debug|Any CPU.Build.0 = Debug|Any CPU {045C64E7-5639-4ECD-BEE3-57597E7CF77E}.Release|Any CPU.ActiveCfg = Release|Any CPU {045C64E7-5639-4ECD-BEE3-57597E7CF77E}.Release|Any CPU.Build.0 = Release|Any CPU {6EB60A4E-87BA-472D-997E-D4C0361A2489}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {6EB60A4E-87BA-472D-997E-D4C0361A2489}.Debug|Any CPU.Build.0 = Debug|Any CPU {6EB60A4E-87BA-472D-997E-D4C0361A2489}.Release|Any CPU.ActiveCfg = Release|Any CPU {6EB60A4E-87BA-472D-997E-D4C0361A2489}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution {E75EECDA-E740-454B-BA83-7B7AC0D9E0A9} = {37EABDC7-EC04-40DB-AADB-73232A885C63} {045C64E7-5639-4ECD-BEE3-57597E7CF77E} = {9AC9FBC2-655D-4D1C-B3B0-8429140C1125} {6EB60A4E-87BA-472D-997E-D4C0361A2489} = {23D17AAC-308D-48E4-9F5F-6B60322BFF9A} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {2D65BA78-C9A7-43A5-91EC-5237C4B9E5C4} EndGlobalSection EndGlobal ================================================ FILE: version.json ================================================ { "$schema": "https://raw.githubusercontent.com/AArnott/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json", "version": "0.2-alpha", "nugetPackageVersion": { "semVer": 2 } }