RSCG – RDG
Generating replacing for minimal API Map
This is how you can use RDG .
The code that you start with is
<Project Sdk="Microsoft.NET.Sdk.Web"> <PropertyGroup> <TargetFramework>net8.0</TargetFramework> <Nullable>enable</Nullable> <ImplicitUsings>enable</ImplicitUsings> <InvariantGlobalization>true</InvariantGlobalization> </PropertyGroup> <ItemGroup> <!--
<PackageReference Include="Microsoft.Extensions.Http"></PackageReference>
--> <PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.0" /> <PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" /> </ItemGroup> <PropertyGroup> <EnableRequestDelegateGenerator>true</EnableRequestDelegateGenerator> </PropertyGroup> <PropertyGroup> <EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles> <CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)\GX</CompilerGeneratedFilesOutputPath> </PropertyGroup> </Project>
The code that you will use is
var builder = WebApplication.CreateBuilder(args); // Add services to the container. // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); var app = builder.Build(); // Configure the HTTP request pipeline. if (app.Environment.IsDevelopment()) { app.UseSwagger(); app.UseSwaggerUI(); } var summaries = new[] { "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" }; app.MapGet("/weatherforecast", () => { var forecast = Enumerable.Range(1, 5).Select(index => new WeatherForecast ( DateOnly.FromDateTime(DateTime.Now.AddDays(index)), Random.Shared.Next(-20, 55), summaries[Random.Shared.Next(summaries.Length)] )) .ToArray(); return forecast; }) .WithName("GetWeatherForecast") .WithOpenApi(); app.Run(); internal record WeatherForecast(DateOnly Date, int TemperatureC, string? Summary) { public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); }
The code that is generated is
//------------------------------------------------------------------------------ // <auto-generated> // This code was generated by a tool. // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // </auto-generated> //------------------------------------------------------------------------------ #nullable enable namespace System.Runtime.CompilerServices { [System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.AspNetCore.Http.RequestDelegateGenerator, Version=8.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60", "8.0.0.0")] [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] file sealed class InterceptsLocationAttribute : Attribute { public InterceptsLocationAttribute(string filePath, int line, int column) { } } } namespace Microsoft.AspNetCore.Http.Generated { using System; using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Text.Json; using System.Text.Json.Serialization.Metadata; using System.Threading.Tasks; using System.IO; using Microsoft.AspNetCore.Antiforgery; using Microsoft.AspNetCore.Routing; using Microsoft.AspNetCore.Routing.Patterns; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Json; using Microsoft.AspNetCore.Http.Metadata; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.FileProviders; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Primitives; using Microsoft.Extensions.Options; using MetadataPopulator = System.Func<System.Reflection.MethodInfo, Microsoft.AspNetCore.Http.RequestDelegateFactoryOptions?, Microsoft.AspNetCore.Http.RequestDelegateMetadataResult>; using RequestDelegateFactoryFunc = System.Func<System.Delegate, Microsoft.AspNetCore.Http.RequestDelegateFactoryOptions, Microsoft.AspNetCore.Http.RequestDelegateMetadataResult?, Microsoft.AspNetCore.Http.RequestDelegateResult>; [System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.AspNetCore.Http.RequestDelegateGenerator, Version=8.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60", "8.0.0.0")] file static class GeneratedRouteBuilderExtensionsCore { private static readonly JsonOptions FallbackJsonOptions = new(); private static readonly string[] GetVerb = new[] { global::Microsoft.AspNetCore.Http.HttpMethods.Get }; [InterceptsLocation(@"D:\gth\RSCG_Examples\v2\rscg_examples\RDG\src\RDGDemo\RDGDemoWebApi\Program.cs", 22, 5)] internal static RouteHandlerBuilder MapGet0( this IEndpointRouteBuilder endpoints, [StringSyntax("Route")] string pattern, Delegate handler) { MetadataPopulator populateMetadata = (methodInfo, options) => { Debug.Assert(options != null, "RequestDelegateFactoryOptions not found."); Debug.Assert(options.EndpointBuilder != null, "EndpointBuilder not found."); options.EndpointBuilder.Metadata.Add(new System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.AspNetCore.Http.RequestDelegateGenerator, Version=8.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60", "8.0.0.0")); options.EndpointBuilder.Metadata.Add(new ProducesResponseTypeMetadata(statusCode: StatusCodes.Status200OK, type: typeof(global::WeatherForecast[]), contentTypes: GeneratedMetadataConstants.JsonContentType)); return new RequestDelegateMetadataResult { EndpointMetadata = options.EndpointBuilder.Metadata.AsReadOnly() }; }; RequestDelegateFactoryFunc createRequestDelegate = (del, options, inferredMetadataResult) => { Debug.Assert(options != null, "RequestDelegateFactoryOptions not found."); Debug.Assert(options.EndpointBuilder != null, "EndpointBuilder not found."); Debug.Assert(options.EndpointBuilder.ApplicationServices != null, "ApplicationServices not found."); Debug.Assert(options.EndpointBuilder.FilterFactories != null, "FilterFactories not found."); var handler = Cast(del, global::WeatherForecast[] () => throw null!); EndpointFilterDelegate? filteredInvocation = null; var serviceProvider = options.ServiceProvider ?? options.EndpointBuilder.ApplicationServices; var jsonOptions = serviceProvider?.GetService<IOptions<JsonOptions>>()?.Value ?? FallbackJsonOptions; var jsonSerializerOptions = jsonOptions.SerializerOptions; jsonSerializerOptions.MakeReadOnly(); var objectJsonTypeInfo = (JsonTypeInfo<object?>)jsonSerializerOptions.GetTypeInfo(typeof(object)); var responseJsonTypeInfo = (JsonTypeInfo<global::WeatherForecast[]?>)jsonSerializerOptions.GetTypeInfo(typeof(global::WeatherForecast[])); if (options.EndpointBuilder.FilterFactories.Count > 0) { filteredInvocation = GeneratedRouteBuilderExtensionsCore.BuildFilterDelegate(ic => { if (ic.HttpContext.Response.StatusCode == 400) { return ValueTask.FromResult<object?>(Results.Empty); } return ValueTask.FromResult<object?>(handler()); }, options.EndpointBuilder, handler.Method); } Task RequestHandler(HttpContext httpContext) { var wasParamCheckFailure = false; if (wasParamCheckFailure) { httpContext.Response.StatusCode = 400; return Task.CompletedTask; } var result = handler(); return GeneratedRouteBuilderExtensionsCore.WriteJsonResponseAsync(httpContext.Response, result, responseJsonTypeInfo); } async Task RequestHandlerFiltered(HttpContext httpContext) { var wasParamCheckFailure = false; if (wasParamCheckFailure) { httpContext.Response.StatusCode = 400; } var result = await filteredInvocation(EndpointFilterInvocationContext.Create(httpContext)); if (result is not null) { await GeneratedRouteBuilderExtensionsCore.ExecuteReturnAsync(result, httpContext, objectJsonTypeInfo); } } RequestDelegate targetDelegate = filteredInvocation is null ? RequestHandler : RequestHandlerFiltered; var metadata = inferredMetadataResult?.EndpointMetadata ?? ReadOnlyCollection<object>.Empty; return new RequestDelegateResult(targetDelegate, metadata); }; return MapCore( endpoints, pattern, handler, GetVerb, populateMetadata, createRequestDelegate); } internal static RouteHandlerBuilder MapCore( this IEndpointRouteBuilder routes, string pattern, Delegate handler, IEnumerable<string>? httpMethods, MetadataPopulator populateMetadata, RequestDelegateFactoryFunc createRequestDelegate) { return RouteHandlerServices.Map(routes, pattern, handler, httpMethods, populateMetadata, createRequestDelegate); } private static T Cast<T>(Delegate d, T _) where T : Delegate { return (T)d; } private static EndpointFilterDelegate BuildFilterDelegate(EndpointFilterDelegate filteredInvocation, EndpointBuilder builder, 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 Task ExecuteReturnAsync(object? obj, HttpContext httpContext, JsonTypeInfo<object?> jsonTypeInfo) { if (obj is IResult r) { return r.ExecuteAsync(httpContext); } else if (obj is string s) { return httpContext.Response.WriteAsync(s); } else { return WriteJsonResponseAsync(httpContext.Response, obj, jsonTypeInfo); } } [UnconditionalSuppressMessage("Trimming", "IL2026:RequiresUnreferencedCode", Justification = "The 'JsonSerializer.IsReflectionEnabledByDefault' feature switch, which is set to false by default for trimmed ASP.NET apps, ensures the JsonSerializer doesn't use Reflection.")] [UnconditionalSuppressMessage("AOT", "IL3050:RequiresDynamicCode", Justification = "See above.")] private static Task WriteJsonResponseAsync<T>(HttpResponse response, T? value, JsonTypeInfo<T?> jsonTypeInfo) { var runtimeType = value?.GetType(); if (jsonTypeInfo.ShouldUseWith(runtimeType)) { return HttpResponseJsonExtensions.WriteAsJsonAsync(response, value, jsonTypeInfo, default); } return response.WriteAsJsonAsync<object?>(value, jsonTypeInfo.Options); } private static bool HasKnownPolymorphism(this JsonTypeInfo jsonTypeInfo) => jsonTypeInfo.Type.IsSealed || jsonTypeInfo.Type.IsValueType || jsonTypeInfo.PolymorphismOptions is not null; private static bool ShouldUseWith(this JsonTypeInfo jsonTypeInfo, [NotNullWhen(false)] Type? runtimeType) => runtimeType is null || jsonTypeInfo.Type == runtimeType || jsonTypeInfo.HasKnownPolymorphism(); } [System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.AspNetCore.Http.RequestDelegateGenerator, Version=8.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60", "8.0.0.0")] file static class GeneratedMetadataConstants { public static readonly string[] JsonContentType = new [] { "application/json" }; public static readonly string[] PlaintextContentType = new [] { "text/plain" }; public static readonly string[] FormFileContentType = new[] { "multipart/form-data" }; public static readonly string[] FormContentType = new[] { "multipart/form-data", "application/x-www-form-urlencoded" }; } [System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.AspNetCore.Http.RequestDelegateGenerator, Version=8.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60", "8.0.0.0")] file sealed class LogOrThrowExceptionHelper { private readonly ILogger? _rdgLogger; private readonly bool _shouldThrow; public LogOrThrowExceptionHelper(IServiceProvider? serviceProvider, RequestDelegateFactoryOptions? options) { var loggerFactory = serviceProvider?.GetRequiredService<ILoggerFactory>(); _rdgLogger = loggerFactory?.CreateLogger("Microsoft.AspNetCore.Http.RequestDelegateGenerator.RequestDelegateGenerator"); _shouldThrow = options?.ThrowOnBadRequest ?? false; } public void RequestBodyIOException(IOException exception) { if (_rdgLogger != null) { _requestBodyIOException(_rdgLogger, exception); } } private static readonly Action<ILogger, Exception?> _requestBodyIOException = LoggerMessage.Define(LogLevel.Debug, new EventId(1, "RequestBodyIOException"), "Reading the request body failed with an IOException."); public void InvalidJsonRequestBody(string parameterTypeName, string parameterName, Exception exception) { if (_shouldThrow) { var message = string.Format(CultureInfo.InvariantCulture, "Failed to read parameter \"{0} {1}\" from the request body as JSON.", parameterTypeName, parameterName); throw new BadHttpRequestException(message, exception); } if (_rdgLogger != null) { _invalidJsonRequestBody(_rdgLogger, parameterTypeName, parameterName, exception); } } private static readonly Action<ILogger, string, string, Exception?> _invalidJsonRequestBody = LoggerMessage.Define<string, string>(LogLevel.Debug, new EventId(2, "InvalidJsonRequestBody"), "Failed to read parameter \"{ParameterType} {ParameterName}\" from the request body as JSON."); public void ParameterBindingFailed(string parameterTypeName, string parameterName, string sourceValue) { if (_shouldThrow) { var message = string.Format(CultureInfo.InvariantCulture, "Failed to bind parameter \"{0} {1}\" from \"{2}\".", parameterTypeName, parameterName, sourceValue); throw new BadHttpRequestException(message); } if (_rdgLogger != null) { _parameterBindingFailed(_rdgLogger, parameterTypeName, parameterName, sourceValue, null); } } private static readonly Action<ILogger, string, string, string, Exception?> _parameterBindingFailed = LoggerMessage.Define<string, string, string>(LogLevel.Debug, new EventId(3, "ParameterBindingFailed"), "Failed to bind parameter \"{ParameterType} {ParameterName}\" from \"{SourceValue}\"."); public void RequiredParameterNotProvided(string parameterTypeName, string parameterName, string source) { if (_shouldThrow) { var message = string.Format(CultureInfo.InvariantCulture, "Required parameter \"{0} {1}\" was not provided from {2}.", parameterTypeName, parameterName, source); throw new BadHttpRequestException(message); } if (_rdgLogger != null) { _requiredParameterNotProvided(_rdgLogger, parameterTypeName, parameterName, source, null); } } private static readonly Action<ILogger, string, string, string, Exception?> _requiredParameterNotProvided = LoggerMessage.Define<string, string, string>(LogLevel.Debug, new EventId(4, "RequiredParameterNotProvided"), "Required parameter \"{ParameterType} {ParameterName}\" was not provided from {Source}."); public void ImplicitBodyNotProvided(string parameterName) { if (_shouldThrow) { var message = string.Format(CultureInfo.InvariantCulture, "Implicit body inferred for parameter \"{0}\" but no body was provided. Did you mean to use a Service instead?", parameterName); throw new BadHttpRequestException(message); } if (_rdgLogger != null) { _implicitBodyNotProvided(_rdgLogger, parameterName, null); } } private static readonly Action<ILogger, string, Exception?> _implicitBodyNotProvided = LoggerMessage.Define<string>(LogLevel.Debug, new EventId(5, "ImplicitBodyNotProvided"), "Implicit body inferred for parameter \"{ParameterName}\" but no body was provided. Did you mean to use a Service instead?"); public void UnexpectedJsonContentType(string? contentType) { if (_shouldThrow) { var message = string.Format(CultureInfo.InvariantCulture, "Expected a supported JSON media type but got \"{0}\".", contentType); throw new BadHttpRequestException(message, StatusCodes.Status415UnsupportedMediaType); } if (_rdgLogger != null) { _unexpectedJsonContentType(_rdgLogger, contentType ?? "(none)", null); } } private static readonly Action<ILogger, string, Exception?> _unexpectedJsonContentType = LoggerMessage.Define<string>(LogLevel.Debug, new EventId(6, "UnexpectedContentType"), "Expected a supported JSON media type but got \"{ContentType}\"."); public void UnexpectedNonFormContentType(string? contentType) { if (_shouldThrow) { var message = string.Format(CultureInfo.InvariantCulture, "Expected a supported form media type but got \"{0}\".", contentType); throw new BadHttpRequestException(message, StatusCodes.Status415UnsupportedMediaType); } if (_rdgLogger != null) { _unexpectedNonFormContentType(_rdgLogger, contentType ?? "(none)", null); } } private static readonly Action<ILogger, string, Exception?> _unexpectedNonFormContentType = LoggerMessage.Define<string>(LogLevel.Debug, new EventId(7, "UnexpectedNonFormContentType"), "Expected a supported form media type but got \"{ContentType}\"."); public void InvalidFormRequestBody(string parameterTypeName, string parameterName, Exception exception) { if (_shouldThrow) { var message = string.Format(CultureInfo.InvariantCulture, "Failed to read parameter \"{0} {1}\" from the request body as form.", parameterTypeName, parameterName); throw new BadHttpRequestException(message, exception); } if (_rdgLogger != null) { _invalidFormRequestBody(_rdgLogger, parameterTypeName, parameterName, exception); } } private static readonly Action<ILogger, string, string, Exception?> _invalidFormRequestBody = LoggerMessage.Define<string, string>(LogLevel.Debug, new EventId(8, "InvalidFormRequestBody"), "Failed to read parameter \"{ParameterType} {ParameterName}\" from the request body as form."); } }
Code and pdf at https://ignatandrei.github.io/RSCG_Examples/v2/docs/RDG