@team-supercharge/oasg 18.0.2 → 18.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (26) hide show
  1. package/README.md +210 -33
  2. package/bin/oasg +2 -0
  3. package/config.schema.yml +37 -0
  4. package/package.json +1 -1
  5. package/targets/dotnet/generate.sh +2 -11
  6. package/targets/dotnet/publish.sh +2 -17
  7. package/targets/dotnet/templates/Project.csproj.mustache +39 -0
  8. package/targets/dotnet-common.sh +48 -0
  9. package/targets/dotnet-system-text-json/generate.sh +6 -0
  10. package/targets/dotnet-system-text-json/generator-config.json +15 -0
  11. package/targets/dotnet-system-text-json/publish.sh +6 -0
  12. package/targets/dotnet-system-text-json/templates/netcore_project.mustache +85 -0
  13. package/targets/dotnet-webapi/generate.sh +2 -11
  14. package/targets/dotnet-webapi/publish.sh +2 -17
  15. package/targets/dotnet-webapi/templates/Project.csproj.mustache +61 -0
  16. package/targets/dotnet-webapi-system-text-json/README.md +234 -0
  17. package/targets/dotnet-webapi-system-text-json/generate.sh +33 -0
  18. package/targets/dotnet-webapi-system-text-json/generator-config.json +29 -0
  19. package/targets/dotnet-webapi-system-text-json/publish.sh +6 -0
  20. package/targets/dotnet-webapi-system-text-json/templates/Project.csproj.mustache +65 -0
  21. package/targets/dotnet-webapi-system-text-json/templates/controller.mustache +7 -0
  22. package/targets/dotnet-webapi-system-text-json/templates/endpointParam.mustache +1 -0
  23. package/targets/dotnet-webapi-system-text-json/templates/minimalEndpoints.mustache +118 -0
  24. package/targets/dotnet-webapi-system-text-json/templates/model.mustache +206 -0
  25. package/targets/dotnet-webapi-system-text-json/templates/paramType.mustache +1 -0
  26. package/targets/dotnet-webapi-system-text-json/templates/serviceCollectionExtensions.mustache +66 -0
@@ -0,0 +1,61 @@
1
+ <Project Sdk="{{projectSdk}}">
2
+ <PropertyGroup>
3
+ <Description>{{packageDescription}}{{^packageDescription}}{{packageName}}{{/packageDescription}}</Description>
4
+ <Copyright>{{packageCopyright}}</Copyright>
5
+ <Authors>{{packageAuthors}}</Authors>
6
+ <TargetFramework>net10.0</TargetFramework>
7
+ <GenerateDocumentationFile>true</GenerateDocumentationFile>
8
+ <PreserveCompilationContext>true</PreserveCompilationContext>
9
+ <Version>{{packageVersion}}</Version>
10
+ {{#nullableReferenceTypes}}
11
+ <Nullable>annotations</Nullable>
12
+ {{/nullableReferenceTypes}}
13
+ {{#isLibrary}}
14
+ <OutputType>Library</OutputType>
15
+ {{/isLibrary}}
16
+ <AssemblyName>{{packageName}}</AssemblyName>
17
+ <PackageId>{{packageName}}</PackageId>
18
+ <UserSecretsId>{{userSecretsGuid}}</UserSecretsId>
19
+ <DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
20
+ <DockerfileContext>..\..</DockerfileContext>
21
+ {{#centralizedPackageVersionManagement}}
22
+ <ManagePackageVersionsCentrally>{{.}}</ManagePackageVersionsCentrally>
23
+ {{/centralizedPackageVersionManagement}}
24
+ </PropertyGroup>
25
+ <ItemGroup>
26
+ {{#useSeparateModelProject}}
27
+ <ProjectReference Include="../{{modelPackage}}/{{modelPackage}}.csproj"/>
28
+ {{/useSeparateModelProject}}
29
+ {{#useFrameworkReference}}
30
+ {{#isLibrary}}
31
+ <FrameworkReference Include="Microsoft.AspNetCore.App" />
32
+ {{/isLibrary}}
33
+ {{/useFrameworkReference}}
34
+ {{^useFrameworkReference}}
35
+ <PackageReference Include="Microsoft.AspNetCore.App" />
36
+ {{/useFrameworkReference}}
37
+ {{^useSeparateModelProject}}
38
+ <PackageReference Include="Microsoft.Extensions.Configuration.Json" {{#usePackageVersions}}Version="{{aspnetCoreVersion}}.0" {{/usePackageVersions}}/>
39
+ {{/useSeparateModelProject}}
40
+ {{#useSwashbuckle}}
41
+ <PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" {{#usePackageVersions}}Version="1.10.8" {{/usePackageVersions}}/>
42
+ {{#useNewtonsoft}}
43
+ <PackageReference Include="Swashbuckle.AspNetCore.Newtonsoft" {{#usePackageVersions}}Version="{{swashbuckleVersion}}" {{/usePackageVersions}}/>
44
+ <PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" {{#usePackageVersions}}Version="{{swashbuckleVersion}}" {{/usePackageVersions}}/>
45
+ {{/useNewtonsoft}}
46
+ {{^useNewtonsoft}}
47
+ <PackageReference Include="Swashbuckle.AspNetCore" {{#usePackageVersions}}Version="{{swashbuckleVersion}}" {{/usePackageVersions}}/>
48
+ {{/useNewtonsoft}}
49
+ <PackageReference Include="Swashbuckle.AspNetCore.Annotations" {{#usePackageVersions}}Version="{{swashbuckleVersion}}" {{/usePackageVersions}}/>
50
+ {{/useSwashbuckle}}
51
+ {{^useSwashbuckle}}
52
+ {{#useNewtonsoft}}
53
+ <PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" {{#usePackageVersions}}Version="{{newtonsoftVersion}}" {{/usePackageVersions}}/>
54
+ {{/useNewtonsoft}}
55
+ {{/useSwashbuckle}}
56
+ <PackageReference Include="JsonSubTypes" {{#usePackageVersions}}Version="1.8.0" {{/usePackageVersions}}/>
57
+ </ItemGroup>
58
+ <ItemGroup>
59
+ <!--<DotNetCliToolReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="{{aspnetCoreVersion}}.0" />-->
60
+ </ItemGroup>
61
+ </Project>
@@ -0,0 +1,234 @@
1
+ # `dotnet-webapi-system-text-json` — Wolverine implementation
2
+
3
+ This target generates an ASP.NET Core server-stub **library** exposing every
4
+ operation as a **minimal-API endpoint** (Native-AOT compatible) with
5
+ System.Text.Json source-generated models. By default each endpoint delegates to a
6
+ generated `I{ApiName}` interface you implement. When the
7
+ `withWolverineImplementation` flag is set, the endpoints instead invoke
8
+ [Wolverine](https://wolverinefx.net) **directly** via `IMessageBus.InvokeAsync` —
9
+ there are no `I{ApiName}` interfaces in that mode.
10
+
11
+ > The examples below assume the package was generated with
12
+ > `packageName = "MyApi"`. Generated request wrappers and the
13
+ > `EndpointRouteBuilderExtensions` live in the `MyApi` namespace; models live in
14
+ > `MyApi.Models`.
15
+
16
+ ## What gets generated (Wolverine mode)
17
+
18
+ Everything lives in a single `EndpointRouteBuilderExtensions.cs`:
19
+
20
+ - A **request wrapper** record per operation, bundling every parameter:
21
+ `AddPetRequest(Pet pet)`, `GetPetByIdRequest(long petId)`,
22
+ `UploadFileRequest(long petId, string? additionalMetadata, Stream? body)`, …
23
+ A distinct type per operation, so request/response pairs never collide.
24
+ - **`Map{ApiName}Endpoints(this IEndpointRouteBuilder)`** (one per API, e.g.
25
+ `MapPetApiEndpoints`) — maps that API's operations as minimal-API endpoints
26
+ that invoke the request through Wolverine and return the result
27
+ (`Results.Ok(result)`, or `Results.NoContent()` when there is no response body).
28
+ Secured operations get `.RequireAuthorization()`.
29
+ - **`MapAll{PackageName}Endpoints(this IEndpointRouteBuilder)`** (e.g.
30
+ `MapAllMyApiEndpoints`) — calls every `Map{ApiName}Endpoints()`.
31
+ - **`ConfigureWolverineMessaging(this WolverineOptions, string localQueueName = "MyApi")`** —
32
+ routes every request type in the assembly to a local queue.
33
+
34
+ The `WolverineFx` package reference is added automatically.
35
+
36
+ ---
37
+
38
+ ## Setup
39
+
40
+ ### 1. Enable the option
41
+
42
+ ```json
43
+ {
44
+ "id": "my-api",
45
+ "type": "dotnet-webapi-system-text-json",
46
+ "source": "source-merged",
47
+ "sourceUrl": "https://api.nuget.org/v3/index.json",
48
+ "apiKey": "apiKey",
49
+ "packageName": "MyApi",
50
+ "withWolverineImplementation": true
51
+ }
52
+ ```
53
+
54
+ ### 2. API host setup
55
+
56
+ Reference the generated package, then wire it up in `Program.cs`:
57
+
58
+ ```csharp
59
+ using Wolverine;
60
+ using MyApi; // generated Map{ApiName}Endpoints / MapAllMyApiEndpoints / ConfigureWolverineMessaging
61
+
62
+ var builder = WebApplication.CreateBuilder(args);
63
+ builder.Services.AddHttpContextAccessor(); // see "Authentication" below
64
+
65
+ builder.Host.UseWolverine(opts =>
66
+ {
67
+ // Route the request types to a local queue.
68
+ opts.ConfigureWolverineMessaging();
69
+
70
+ // Static codegen (see below). Pre-generate with `dotnet run -- codegen write`.
71
+ opts.CodeGeneration.TypeLoadMode = JasperFx.CodeGeneration.TypeLoadMode.Static;
72
+
73
+ // Optional: force every InvokeAsync to run locally (in-process). With this
74
+ // on, an invocation that would otherwise be sent to a remote transport
75
+ // throws instead. Turn it on if this service must never make remote calls.
76
+ // opts.EnableRemoteInvocation = false;
77
+ });
78
+
79
+ var app = builder.Build();
80
+
81
+ app.UseAuthentication();
82
+ app.UseAuthorization();
83
+
84
+ app.MapAllMyApiEndpoints(); // aggregate; or call Map{ApiName}Endpoints() individually
85
+
86
+ app.Run();
87
+ ```
88
+
89
+ ### 3. Static codegen
90
+
91
+ Setting `opts.CodeGeneration.TypeLoadMode = TypeLoadMode.Static` (above) stops
92
+ Wolverine from compiling handler code at runtime. Pre-generate it as part of your
93
+ build/deploy:
94
+
95
+ ```bash
96
+ dotnet run -- codegen write
97
+ ```
98
+
99
+ (Alternatively, drop that line and reference `WolverineFx.RuntimeCompilation` to
100
+ opt back into runtime Roslyn compilation.)
101
+
102
+ ---
103
+
104
+ ## Usage
105
+
106
+ ### Request handling
107
+
108
+ Provide a handler for each generated `*Request` type. Wolverine discovers
109
+ handlers by convention (a `Handle`/`HandleAsync` method); the return type must
110
+ match the operation's response model (or `Task`/nothing for no-content
111
+ operations).
112
+
113
+ ```csharp
114
+ using MyApi; // *Request types
115
+ using MyApi.Models; // Pet, ...
116
+
117
+ public class PetHandlers
118
+ {
119
+ // Operation with a response body -> return the response model
120
+ public Task<Pet> Handle(AddPetRequest request)
121
+ => Task.FromResult(request.pet);
122
+
123
+ public async Task<Pet> Handle(GetPetByIdRequest request)
124
+ => await _repository.GetAsync(request.petId)
125
+ ?? throw new PetNotFoundException(request.petId);
126
+
127
+ // No-response-body operation -> return Task (the endpoint returns NoContent)
128
+ public Task Handle(DeletePetRequest request)
129
+ => _repository.DeleteAsync(request.petId);
130
+ }
131
+ ```
132
+
133
+ ### Authentication
134
+
135
+ Secured operations get `.RequireAuthorization()` on the generated endpoint, so
136
+ authorization is enforced by ASP.NET Core **before** the handler runs. Register
137
+ the matching authentication scheme and authorization policy in the host — e.g.
138
+ for the `api_key` policy emitted for an API-key-secured operation:
139
+
140
+ ```csharp
141
+ builder.Services
142
+ .AddAuthentication("ApiKey")
143
+ .AddScheme<AuthenticationSchemeOptions, ApiKeyAuthHandler>("ApiKey", _ => { });
144
+
145
+ builder.Services.AddAuthorization(options =>
146
+ options.AddPolicy("api_key", policy => policy.RequireAuthenticatedUser()));
147
+ ```
148
+
149
+ Because `InvokeAsync` runs the handler **in-process** within the request, the
150
+ authenticated user flows through `HttpContext`. Read it in a handler via
151
+ `IHttpContextAccessor` (registered with `AddHttpContextAccessor()` above):
152
+
153
+ ```csharp
154
+ public class GetPetByIdHandler(IHttpContextAccessor http)
155
+ {
156
+ public async Task<Pet> Handle(GetPetByIdRequest request)
157
+ {
158
+ var user = http.HttpContext!.User; // authenticated principal
159
+ var tenant = user.FindFirst("tenant")?.Value;
160
+ return await _repository.GetAsync(request.petId, tenant);
161
+ }
162
+ }
163
+ ```
164
+
165
+ ### Error handling
166
+
167
+ Wolverine scopes retry rules **per handler** (not on the routing options), so
168
+ `ConfigureWolverineMessaging` sets no retry policy. Opt into fail-fast where you
169
+ want it, on the handler:
170
+
171
+ ```csharp
172
+ using Wolverine;
173
+ using Wolverine.ErrorHandling;
174
+
175
+ public class GetPetByIdHandler
176
+ {
177
+ // No retries: a failure surfaces immediately.
178
+ public static void Configure(HandlerChain chain) => chain.OnAnyException().Discard();
179
+
180
+ public Task<Pet> Handle(GetPetByIdRequest request) => /* ... */;
181
+ }
182
+ ```
183
+
184
+ With no retries, a handler exception propagates straight back through
185
+ `InvokeAsync` into the endpoint. Map domain exceptions to HTTP responses
186
+ host-side with an `IExceptionHandler` + ProblemDetails:
187
+
188
+ ```csharp
189
+ public sealed class DomainExceptionHandler(IProblemDetailsService problemDetails)
190
+ : IExceptionHandler
191
+ {
192
+ public async ValueTask<bool> TryHandleAsync(
193
+ HttpContext context, Exception exception, CancellationToken ct)
194
+ {
195
+ var status = exception switch
196
+ {
197
+ PetNotFoundException => StatusCodes.Status404NotFound,
198
+ ValidationException => StatusCodes.Status400BadRequest,
199
+ _ => 0
200
+ };
201
+ if (status == 0) return false; // not a domain error -> let it bubble
202
+
203
+ context.Response.StatusCode = status;
204
+ return await problemDetails.TryWriteAsync(new ProblemDetailsContext
205
+ {
206
+ HttpContext = context,
207
+ ProblemDetails = { Title = exception.Message, Status = status }
208
+ });
209
+ }
210
+ }
211
+ ```
212
+
213
+ ```csharp
214
+ // Program.cs
215
+ builder.Services.AddProblemDetails();
216
+ builder.Services.AddExceptionHandler<DomainExceptionHandler>();
217
+ // ...
218
+ app.UseExceptionHandler();
219
+ ```
220
+
221
+ ---
222
+
223
+ ## Notes & limitations
224
+
225
+ - **Without the flag**, the same endpoints delegate to a generated `I{ApiName}`
226
+ interface (resolved from DI) that you implement directly — no Wolverine.
227
+ - **Conflicting request/response pairs** are avoided because every operation gets
228
+ its own wrapper type (e.g. `AddPetRequest` and `UpdatePetRequest`, even though
229
+ both wrap a `Pet`).
230
+ - **File uploads:** the wrapper carries the path/query parameters alongside the
231
+ body, so they reach the handler. The body is a `System.IO.Stream` — fine for
232
+ the in-process local-queue routing used here, but a `Stream` is not
233
+ serializable, so if you re-route these requests to a remote transport
234
+ (RabbitMQ, Azure Service Bus, …) buffer the body to a `byte[]` instead.
@@ -0,0 +1,33 @@
1
+ #!/bin/bash
2
+
3
+ source $(dirname "$0")/../common.sh
4
+ source $(dirname "$0")/../dotnet-common.sh
5
+
6
+ # Pass the Wolverine flag to the generator only when enabled, so the mustache
7
+ # section {{#withWolverineImplementation}} stays falsy otherwise (a string
8
+ # "false" additional-property would read as truthy).
9
+ if [ "${withWolverineImplementation}" = "true" ]; then
10
+ generatorCustomArgs="$generatorCustomArgs --additional-properties=withWolverineImplementation=true"
11
+ fi
12
+
13
+ dotnet_generate
14
+
15
+ # The aggregate minimal-API endpoints file is emitted by a SupportingFiles
16
+ # template (generator-config.json "files"), which can't template its output
17
+ # folder, so it lands at the output root. Move it into the package source dir
18
+ # so it's part of the project.
19
+ endpointsFile="out/$targetId/EndpointRouteBuilderExtensions.cs"
20
+ if [ -f "$endpointsFile" ]; then
21
+ destFile="out/$targetId/src/$packageName/EndpointRouteBuilderExtensions.cs"
22
+ mv "$endpointsFile" "$destFile"
23
+ # The generator only exposes the verb as "HttpGet"/"HttpPost"/..., so the
24
+ # template emits endpoints.MapHttpGet(...); rewrite to the real minimal-API
25
+ # method name endpoints.MapGet(...).
26
+ sed -i.bak 's/\.MapHttp/.Map/g' "$destFile" && rm -f "$destFile.bak"
27
+ fi
28
+
29
+ # Same for the JSON-options service-collection extension (SupportingFiles file).
30
+ serviceExtFile="out/$targetId/ServiceCollectionExtensions.cs"
31
+ if [ -f "$serviceExtFile" ]; then
32
+ mv "$serviceExtFile" "out/$targetId/src/$packageName/ServiceCollectionExtensions.cs"
33
+ fi
@@ -0,0 +1,29 @@
1
+ {
2
+ "inlineSchemaOptions": {
3
+ "ARRAY_ITEM_SUFFIX": "",
4
+ "MAP_ITEM_SUFFIX": "",
5
+ "SKIP_SCHEMA_REUSE": "true"
6
+ },
7
+ "additionalProperties": {
8
+ "aspnetCoreVersion": "8.0",
9
+ "operationIsAsync": true,
10
+ "buildTarget": "library",
11
+ "generateBody": false,
12
+ "nullableReferenceTypes": true,
13
+ "operationResultTask": true,
14
+ "useNewtonsoft": false,
15
+ "enumNameSuffix": "",
16
+ "enumValueSuffix": "",
17
+ "wolverineVersion": "6.10.0"
18
+ },
19
+ "files": {
20
+ "minimalEndpoints.mustache": {
21
+ "destinationFilename": "EndpointRouteBuilderExtensions.cs",
22
+ "templateType": "SupportingFiles"
23
+ },
24
+ "serviceCollectionExtensions.mustache": {
25
+ "destinationFilename": "ServiceCollectionExtensions.cs",
26
+ "templateType": "SupportingFiles"
27
+ }
28
+ }
29
+ }
@@ -0,0 +1,6 @@
1
+ #!/bin/bash
2
+
3
+ source $(dirname "$0")/../common.sh
4
+ source $(dirname "$0")/../dotnet-common.sh
5
+
6
+ dotnet_publish
@@ -0,0 +1,65 @@
1
+ <Project Sdk="{{projectSdk}}">
2
+ <PropertyGroup>
3
+ <Description>{{packageDescription}}{{^packageDescription}}{{packageName}}{{/packageDescription}}</Description>
4
+ <Copyright>{{packageCopyright}}</Copyright>
5
+ <Authors>{{packageAuthors}}</Authors>
6
+ <TargetFramework>net10.0</TargetFramework>
7
+ <IsAotCompatible>true</IsAotCompatible>
8
+ <GenerateDocumentationFile>true</GenerateDocumentationFile>
9
+ <PreserveCompilationContext>true</PreserveCompilationContext>
10
+ <Version>{{packageVersion}}</Version>
11
+ {{#nullableReferenceTypes}}
12
+ <Nullable>annotations</Nullable>
13
+ {{/nullableReferenceTypes}}
14
+ {{#isLibrary}}
15
+ <OutputType>Library</OutputType>
16
+ {{/isLibrary}}
17
+ <AssemblyName>{{packageName}}</AssemblyName>
18
+ <PackageId>{{packageName}}</PackageId>
19
+ <UserSecretsId>{{userSecretsGuid}}</UserSecretsId>
20
+ <DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
21
+ <DockerfileContext>..\..</DockerfileContext>
22
+ {{#centralizedPackageVersionManagement}}
23
+ <ManagePackageVersionsCentrally>{{.}}</ManagePackageVersionsCentrally>
24
+ {{/centralizedPackageVersionManagement}}
25
+ </PropertyGroup>
26
+ <ItemGroup>
27
+ {{#withWolverineImplementation}}
28
+ <PackageReference Include="WolverineFx" Version="{{wolverineVersion}}" />
29
+ {{/withWolverineImplementation}}
30
+ {{#useSeparateModelProject}}
31
+ <ProjectReference Include="../{{modelPackage}}/{{modelPackage}}.csproj"/>
32
+ {{/useSeparateModelProject}}
33
+ {{#useFrameworkReference}}
34
+ {{#isLibrary}}
35
+ <FrameworkReference Include="Microsoft.AspNetCore.App" />
36
+ {{/isLibrary}}
37
+ {{/useFrameworkReference}}
38
+ {{^useFrameworkReference}}
39
+ <PackageReference Include="Microsoft.AspNetCore.App" />
40
+ {{/useFrameworkReference}}
41
+ {{^useSeparateModelProject}}
42
+ <PackageReference Include="Microsoft.Extensions.Configuration.Json" {{#usePackageVersions}}Version="{{aspnetCoreVersion}}.0" {{/usePackageVersions}}/>
43
+ {{/useSeparateModelProject}}
44
+ {{#useSwashbuckle}}
45
+ <PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" {{#usePackageVersions}}Version="1.10.8" {{/usePackageVersions}}/>
46
+ {{#useNewtonsoft}}
47
+ <PackageReference Include="Swashbuckle.AspNetCore.Newtonsoft" {{#usePackageVersions}}Version="{{swashbuckleVersion}}" {{/usePackageVersions}}/>
48
+ <PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" {{#usePackageVersions}}Version="{{swashbuckleVersion}}" {{/usePackageVersions}}/>
49
+ {{/useNewtonsoft}}
50
+ {{^useNewtonsoft}}
51
+ <PackageReference Include="Swashbuckle.AspNetCore" {{#usePackageVersions}}Version="{{swashbuckleVersion}}" {{/usePackageVersions}}/>
52
+ {{/useNewtonsoft}}
53
+ <PackageReference Include="Swashbuckle.AspNetCore.Annotations" {{#usePackageVersions}}Version="{{swashbuckleVersion}}" {{/usePackageVersions}}/>
54
+ {{/useSwashbuckle}}
55
+ {{^useSwashbuckle}}
56
+ {{#useNewtonsoft}}
57
+ <PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" {{#usePackageVersions}}Version="{{newtonsoftVersion}}" {{/usePackageVersions}}/>
58
+ {{/useNewtonsoft}}
59
+ {{/useSwashbuckle}}
60
+ <PackageReference Include="JsonSubTypes" {{#usePackageVersions}}Version="1.8.0" {{/usePackageVersions}}/>
61
+ </ItemGroup>
62
+ <ItemGroup>
63
+ <!--<DotNetCliToolReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="{{aspnetCoreVersion}}.0" />-->
64
+ </ItemGroup>
65
+ </Project>
@@ -0,0 +1,7 @@
1
+ {{>partial_header}}
2
+ // Intentionally empty.
3
+ //
4
+ // This target exposes its operations as minimal-API endpoints instead of MVC
5
+ // controllers (minimal APIs are Native-AOT compatible; MVC controllers are not).
6
+ // See {{packageName}}.EndpointRouteBuilderExtensions.MapAllEndpoints and the
7
+ // generated I{ApiName} interfaces in EndpointRouteBuilderExtensions.cs.
@@ -0,0 +1 @@
1
+ {{#isPathParam}}[FromRoute(Name = "{{baseName}}")] {{/isPathParam}}{{#isQueryParam}}[FromQuery(Name = "{{baseName}}")] {{/isQueryParam}}{{#isHeaderParam}}[FromHeader(Name = "{{baseName}}")] {{/isHeaderParam}}{{#isBodyParam}}[FromBody] {{/isBodyParam}}{{#isFormParam}}[FromForm] {{/isFormParam}}
@@ -0,0 +1,118 @@
1
+ // <auto-generated/>
2
+ #nullable enable
3
+ using System.Collections.Generic;
4
+ using System.Threading;
5
+ using System.Threading.Tasks;
6
+ using Microsoft.AspNetCore.Builder;
7
+ using Microsoft.AspNetCore.Http;
8
+ using Microsoft.AspNetCore.Mvc;
9
+ using Microsoft.AspNetCore.Routing;
10
+ {{#withWolverineImplementation}}
11
+ using Microsoft.Extensions.DependencyInjection;
12
+ using Wolverine;
13
+ {{/withWolverineImplementation}}
14
+ using {{packageName}}.Models;
15
+
16
+ namespace {{packageName}}
17
+ {
18
+ {{^withWolverineImplementation}}
19
+ {{#apiInfo}}
20
+ {{#apis}}
21
+ /// <summary>
22
+ /// Application logic for the {{classname}} endpoints. Register an implementation in DI.
23
+ /// </summary>
24
+ public interface I{{classname}}
25
+ {
26
+ {{#operations}}
27
+ {{#operation}}
28
+ Task<IResult> {{operationId}}({{#allParams}}{{>paramType}} {{paramName}}, {{/allParams}}CancellationToken cancellationToken);
29
+ {{/operation}}
30
+ {{/operations}}
31
+ }
32
+
33
+ {{/apis}}
34
+ {{/apiInfo}}
35
+ {{/withWolverineImplementation}}
36
+ {{#withWolverineImplementation}}
37
+ {{#apiInfo}}
38
+ {{#apis}}
39
+ {{#operations}}
40
+ {{#operation}}
41
+ /// <summary>Wolverine request for {{classname}}.{{operationId}}, carrying every parameter.</summary>
42
+ public record {{operationId}}Request({{#allParams}}{{>paramType}} {{paramName}}{{^-last}}, {{/-last}}{{/allParams}});
43
+ {{/operation}}
44
+ {{/operations}}
45
+ {{/apis}}
46
+ {{/apiInfo}}
47
+ {{/withWolverineImplementation}}
48
+
49
+ /// <summary>
50
+ /// Maps every generated API operation as a minimal-API endpoint.
51
+ {{^withWolverineImplementation}}
52
+ /// Each endpoint delegates to the matching <c>I{ApiName}</c> implementation from DI.
53
+ {{/withWolverineImplementation}}
54
+ {{#withWolverineImplementation}}
55
+ /// Each endpoint invokes the request through Wolverine (IMessageBus.InvokeAsync).
56
+ {{/withWolverineImplementation}}
57
+ /// </summary>
58
+ public static class EndpointRouteBuilderExtensions
59
+ {
60
+ {{#apiInfo}}
61
+ {{#apis}}
62
+ /// <summary>Maps the {{classname}} operations as minimal-API endpoints.</summary>
63
+ public static IEndpointRouteBuilder Map{{classname}}Endpoints(this IEndpointRouteBuilder endpoints)
64
+ {
65
+ {{#operations}}
66
+ {{#operation}}
67
+ endpoints.Map{{httpMethod}}("{{{basePathWithoutHost}}}{{{path}}}",
68
+ {{#withWolverineImplementation}}async {{/withWolverineImplementation}}({{#allParams}}{{>endpointParam}}{{>paramType}} {{paramName}}, {{/allParams}}[FromServices] {{^withWolverineImplementation}}I{{classname}} handler{{/withWolverineImplementation}}{{#withWolverineImplementation}}IMessageBus messageBus{{/withWolverineImplementation}}, CancellationToken cancellationToken)
69
+ => {{^withWolverineImplementation}}handler.{{operationId}}({{#allParams}}{{paramName}}, {{/allParams}}cancellationToken){{/withWolverineImplementation}}{{#withWolverineImplementation}}{{#returnType}}Results.Ok(await messageBus.InvokeAsync<{{{returnType}}}>(new {{operationId}}Request({{#allParams}}{{paramName}}{{^-last}}, {{/-last}}{{/allParams}}), cancellationToken)){{/returnType}}{{^returnType}}await Handle(messageBus, new {{operationId}}Request({{#allParams}}{{paramName}}{{^-last}}, {{/-last}}{{/allParams}}), cancellationToken){{/returnType}}{{/withWolverineImplementation}}){{#hasAuthMethods}}
70
+ .RequireAuthorization(){{/hasAuthMethods}};
71
+ {{/operation}}
72
+ {{/operations}}
73
+ return endpoints;
74
+ }
75
+
76
+ {{/apis}}
77
+ {{/apiInfo}}
78
+ /// <summary>Maps the endpoints of every generated API.</summary>
79
+ public static IEndpointRouteBuilder MapAll{{packageName}}Endpoints(this IEndpointRouteBuilder endpoints)
80
+ {
81
+ {{#apiInfo}}
82
+ {{#apis}}
83
+ endpoints.Map{{classname}}Endpoints();
84
+ {{/apis}}
85
+ {{/apiInfo}}
86
+ return endpoints;
87
+ }
88
+
89
+ {{#withWolverineImplementation}}
90
+ private static async Task<IResult> Handle<TRequest>(IMessageBus messageBus, TRequest request, CancellationToken cancellationToken)
91
+ {
92
+ await messageBus.InvokeAsync(request!, cancellationToken);
93
+ return Results.NoContent();
94
+ }
95
+
96
+ /// <summary>
97
+ /// Routes every generated request type (in this assembly) to a local queue.
98
+ /// </summary>
99
+ public static WolverineOptions ConfigureWolverineMessaging(this WolverineOptions options, string localQueueName = "{{packageName}}")
100
+ {
101
+ options.Publish(rule =>
102
+ {
103
+ {{#apiInfo}}
104
+ {{#apis}}
105
+ {{#operations}}
106
+ {{#operation}}
107
+ rule.Message<{{operationId}}Request>();
108
+ {{/operation}}
109
+ {{/operations}}
110
+ {{/apis}}
111
+ {{/apiInfo}}
112
+ rule.ToLocalQueue(localQueueName);
113
+ });
114
+ return options;
115
+ }
116
+ {{/withWolverineImplementation}}
117
+ }
118
+ }