@team-supercharge/oasg 18.0.1 → 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.
- package/README.md +210 -33
- package/bin/oasg +2 -0
- package/config.schema.yml +37 -0
- package/package.json +1 -1
- package/targets/dotnet/generate.sh +2 -11
- package/targets/dotnet/publish.sh +2 -17
- package/targets/dotnet/templates/Project.csproj.mustache +39 -0
- package/targets/dotnet-common.sh +48 -0
- package/targets/dotnet-system-text-json/generate.sh +6 -0
- package/targets/dotnet-system-text-json/generator-config.json +15 -0
- package/targets/dotnet-system-text-json/publish.sh +6 -0
- package/targets/dotnet-system-text-json/templates/netcore_project.mustache +85 -0
- package/targets/dotnet-webapi/generate.sh +2 -11
- package/targets/dotnet-webapi/publish.sh +2 -17
- package/targets/dotnet-webapi/templates/Project.csproj.mustache +61 -0
- package/targets/dotnet-webapi-system-text-json/README.md +234 -0
- package/targets/dotnet-webapi-system-text-json/generate.sh +33 -0
- package/targets/dotnet-webapi-system-text-json/generator-config.json +29 -0
- package/targets/dotnet-webapi-system-text-json/publish.sh +6 -0
- package/targets/dotnet-webapi-system-text-json/templates/Project.csproj.mustache +65 -0
- package/targets/dotnet-webapi-system-text-json/templates/controller.mustache +7 -0
- package/targets/dotnet-webapi-system-text-json/templates/endpointParam.mustache +1 -0
- package/targets/dotnet-webapi-system-text-json/templates/minimalEndpoints.mustache +118 -0
- package/targets/dotnet-webapi-system-text-json/templates/model.mustache +206 -0
- package/targets/dotnet-webapi-system-text-json/templates/paramType.mustache +1 -0
- package/targets/dotnet-webapi-system-text-json/templates/serviceCollectionExtensions.mustache +66 -0
- package/targets/react/templates/hook.mustache +29 -6
|
@@ -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,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
|
+
}
|