Skip to content
Merged
31 changes: 22 additions & 9 deletions samples/WebApplication.Shared/WebApplication.Shared.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,40 @@

<PropertyGroup>
<OutputType>Library</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<OpenApiMode>Swashbuckle</OpenApiMode>
<OpenApiMode>Swashbuckle-net8</OpenApiMode>
<UseLocallyBuiltPackage>true</UseLocallyBuiltPackage>
</PropertyGroup>

<PropertyGroup Condition=" '$(OpenApiMode)' == 'Swashbuckle-net8'">
<TargetFramework>net8.0</TargetFramework>
<DefineConstants>$(DefineConstants);USE_SWASHBUCKLE;USE_SWASHBUCKLE_NET8</DefineConstants>
</PropertyGroup>

<PropertyGroup Condition=" '$(OpenApiMode)' == 'Swashbuckle-net10'">
<TargetFramework>net10.0</TargetFramework>
<DefineConstants>$(DefineConstants);USE_SWASHBUCKLE;USE_SWASHBUCKLE_NET10</DefineConstants>
</PropertyGroup>

<PropertyGroup Condition=" '$(OpenApiMode)' == 'MicrosoftAndScalar'">
<TargetFramework>net9.0</TargetFramework>
<DefineConstants>USE_MICROSOFT_OPENAPI_AND_SCALAR</DefineConstants>
<TargetFramework>net10.0</TargetFramework>
<DefineConstants>$(DefineConstants);USE_MICROSOFT_OPENAPI_AND_SCALAR</DefineConstants>
</PropertyGroup>

<ItemGroup Condition=" '$(OpenApiMode)' == 'MicrosoftAndScalar'">
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="9.0.0-preview.4.24267.6"/>
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="10.0.0"/>
<PackageReference Include="Scalar.AspNetCore" Version="1.1.1"/>
</ItemGroup>

<ItemGroup Condition=" '$(OpenApiMode)' == 'Swashbuckle'">
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.2"/>
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0"/>
</ItemGroup>
<ItemGroup Condition=" '$(OpenApiMode)' == 'Swashbuckle-net8'">
<PackageReference Include="Swashbuckle.AspNetCore.Annotations" Version="6.4.0"/>
</ItemGroup>

<ItemGroup Condition=" '$(OpenApiMode)' == 'Swashbuckle-net10'">
<PackageReference Include="Swashbuckle.AspNetCore.Annotations" Version="10.0.1" />
</ItemGroup>


<ItemGroup Condition=" '$(UseLocallyBuiltPackage)' != ''">
<PackageReference Include="Vogen" Version="999.9.*"/>
Expand Down
10 changes: 8 additions & 2 deletions samples/WebApplication/OrdersController.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc;

[Route("api/[controller]")]
public class OrdersController : ControllerBase
Expand All @@ -10,21 +10,27 @@ public class OrdersController : ControllerBase
];

[HttpGet]
[Produces(typeof(IEnumerable<Order>))]
public IActionResult CurrentOrders()
{
return Ok(_orders);
}

[HttpGet, Route("customer/{customerName}")]
[Produces(typeof(IEnumerable<Order>))]
public IActionResult GetByName(CustomerName customerName)
{
return Ok(_orders.Where(o => o.CustomerName == customerName));
}

[HttpGet, Route("{orderId}")]
[Produces(typeof(Order))]
public IActionResult GetByOrderId(OrderId orderId)
{
return Ok(_orders.Where(o => o.OrderId == orderId));
var order = _orders.SingleOrDefault(o => o.OrderId == orderId);
if (order == null)
return new NotFoundResult();
return Ok(order);
}
}

30 changes: 24 additions & 6 deletions samples/WebApplication/Program.cs
Original file line number Diff line number Diff line change
@@ -1,16 +1,26 @@
#pragma warning disable ASPDEPR002

using Microsoft.OpenApi;
using Vogen;
using WebApplication.Shared;

#if USE_SWASHBUCKLE
[assembly: VogenDefaults(openApiSchemaCustomizations: OpenApiSchemaCustomizations.GenerateSwashbuckleMappingExtensionMethod)]
#if USE_SWASHBUCKLE_NET8
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Models;

[assembly: VogenDefaults(openApiSchemaCustomizations: OpenApiSchemaCustomizations.GenerateSwashbuckleMappingExtensionMethod)]
#endif
#if USE_SWASHBUCKLE_NET10
using System.Text.Json.Nodes;
using Microsoft.OpenApi;

[assembly: VogenDefaults(openApiSchemaCustomizations: OpenApiSchemaCustomizations.GenerateSwashbuckleMappingExtensionMethod)]
#endif
#if USE_MICROSOFT_OPENAPI_AND_SCALAR
using Microsoft.AspNetCore.OpenApi;
using Scalar.AspNetCore;
[assembly: VogenDefaults(openApiSchemaCustomizations: OpenApiSchemaCustomizations.GenerateOpenApiMappingExtensionMethod)]
using Microsoft.AspNetCore.OpenApi;
using Microsoft.OpenApi;
using Scalar.AspNetCore;

[assembly: VogenDefaults(openApiSchemaCustomizations: OpenApiSchemaCustomizations.GenerateOpenApiMappingExtensionMethod)]
#endif


Expand Down Expand Up @@ -116,7 +126,15 @@
{
var parameter = generatedOperation.Parameters?[0];
parameter?.Description = "The ID of the historical weather report (example only - always returns the same weather report)";

#if USE_MICROSOFT_OPENAPI_AND_SCALAR
parameter?.Examples?.Add("example1", new OpenApiExample { Value = Guid.NewGuid().ToString() });
#elif USE_SWASHBUCKLE_NET8
parameter?.Examples?.Add("example1", new OpenApiExample { Value = new OpenApiString(Guid.NewGuid().ToString()) });
#elif USE_SWASHBUCKLE_NET10
parameter?.Examples?.Add("example1", new OpenApiExample() { Value = JsonValue.Create(Guid.NewGuid().ToString()) });
#endif

return generatedOperation;
});

Expand Down
8 changes: 4 additions & 4 deletions samples/WebApplication/README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
This is a sample web application. It shows how to use value objects
This is a sample web application. It shows how to use value objects
in a web app.

In particular, it shows how to get Vogen to generate the necessary code to
Expand All @@ -7,9 +7,9 @@ customize the OpenAPI schema types for value object (e.g. `CustomerName` is a `s
The project can also be switched to use `Microsof.OpenApi` and 'Scalar'. This targets .NET9. This is merely here as
a placeholder. It was added to see if there was a way, similiar to Swashbuckle, to customize the schema types of
value objects. I haven't found a way to do that yet though as it's not as customizable as Swashbuckle.
You can switch by changing `<OpenApiMode>Swashbuckle</OpenApiMode>` in the `.csproj` file. The other mode is
`MicrosoftAndScalar` (and the other launch-setting is `https openapi and scalar`)
`
You can switch by changing `<OpenApiMode>` in the `.csproj` file to `MicrosoftAndScalar`, `Swashbuckle-net8`,
or `Swashbuckle-net10`.
The launch settings for `MicrosoftAndScalar` is `https openapi and scalar`.

The companion project to this is `WebApplicationConsumer` which demonstrates how to consume an API that uses value
object as parameters.
6 changes: 5 additions & 1 deletion samples/WebApplication/Types.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Vogen;
using Vogen;
using WebApplication.Shared;

record WeatherForecast(ForecastDate Date, Centigrade TemperatureC, Farenheit TemperatureF, string? Summary, City City);

Expand Down Expand Up @@ -35,5 +36,8 @@ public class Order
public OrderId OrderId { get; init; }

public CustomerName CustomerName { get; init; } = CustomerName.From("");

public SharedStruct SharedStruct { get; init; }
public SharedStruct? SharedStructOrNull { get; init; }
}

24 changes: 16 additions & 8 deletions samples/WebApplication/WebApplication.csproj
Original file line number Diff line number Diff line change
@@ -1,38 +1,46 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<UseLocallyBuiltPackage>true</UseLocallyBuiltPackage>
<OpenApiMode>MicrosoftAndScalar</OpenApiMode>
<OpenApiMode>Swashbuckle-net8</OpenApiMode>
</PropertyGroup>

<PropertyGroup Condition=" '$(OpenApiMode)' == 'Swashbuckle'">
<PropertyGroup Condition=" '$(OpenApiMode)' == 'Swashbuckle-net8'">
<TargetFramework>net8.0</TargetFramework>
<DefineConstants>USE_SWASHBUCKLE</DefineConstants>
<DefineConstants>$(DefineConstants);USE_SWASHBUCKLE;USE_SWASHBUCKLE_NET8</DefineConstants>
</PropertyGroup>

<PropertyGroup Condition=" '$(OpenApiMode)' == 'Swashbuckle-net10'">
<TargetFramework>net10.0</TargetFramework>
<DefineConstants>$(DefineConstants);USE_SWASHBUCKLE;USE_SWASHBUCKLE_NET10</DefineConstants>
</PropertyGroup>

<PropertyGroup Condition=" '$(OpenApiMode)' == 'MicrosoftAndScalar'">
<TargetFramework>net10.0</TargetFramework>
<DefineConstants>USE_MICROSOFT_OPENAPI_AND_SCALAR</DefineConstants>
<DefineConstants>$(DefineConstants);USE_MICROSOFT_OPENAPI_AND_SCALAR</DefineConstants>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Refit" Version="8.0.0"/>
<!-- <PackageReference Include="System.Text.Json" Version="8.0.5" />-->
</ItemGroup>

<ItemGroup Condition=" '$(OpenApiMode)' == 'MicrosoftAndScalar'">
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="10.0.0"/>
<PackageReference Include="Scalar.AspNetCore" Version="1.1.1"/>
</ItemGroup>

<ItemGroup Condition=" '$(OpenApiMode)' == 'Swashbuckle'">
<ItemGroup Condition=" '$(OpenApiMode)' == 'Swashbuckle-net8'">
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.2"/>
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0"/>
</ItemGroup>

<ItemGroup Condition=" '$(OpenApiMode)' == 'Swashbuckle-net10'">
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="10.0.0"/>
<PackageReference Include="Swashbuckle.AspNetCore" Version="10.0.1" />
</ItemGroup>

<ItemGroup Condition=" '$(UseLocallyBuiltPackage)' != ''">
<PackageReference Include="Vogen" Version="999.9.*"/>
</ItemGroup>
Expand Down
44 changes: 19 additions & 25 deletions src/Vogen/GenerateCodeForAspNetCoreOpenApiSchema.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System.Collections.Generic;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Text;
Expand All @@ -17,6 +17,13 @@ internal static void WriteOpenApiExtensionMethodMapping(
VogenKnownSymbols knownSymbols,
string className)
{
var openApiVersion = OpenApiSchemaUtils.DetermineOpenApiVersionBeingUsed(knownSymbols);

if (!OpenApiSchemaUtils.IsOpenApiOptionsReferenced(knownSymbols) || openApiVersion is OpenApiVersionBeingUsed.None)
{
return;
}

var items = workItems.Select(eachItem =>
new Item
{
Expand All @@ -27,23 +34,14 @@ internal static void WriteOpenApiExtensionMethodMapping(
UnderlyingTypeFullName = eachItem.UnderlyingType.EscapedFullName()
}).ToList();

OpenApiVersionBeingUsed v = IsOpenApi2xReferenced(knownSymbols) ? OpenApiVersionBeingUsed.TwoPlus :
IsOpenApi1xReferenced(knownSymbols) ? OpenApiVersionBeingUsed.One : OpenApiVersionBeingUsed.None;

if (v is OpenApiVersionBeingUsed.None)
{
return;
}

WriteOpenApiExtensionMethodMapping(context, items, knownSymbols, className, v);
WriteOpenApiExtensionMethodMapping(context, items, className, openApiVersion);
}

private static void WriteOpenApiExtensionMethodMapping(
SourceProductionContext context,
List<Item> workItems,
VogenKnownSymbols knownSymbols,
string className,
OpenApiVersionBeingUsed v)
OpenApiVersionBeingUsed openApiVersion)
{
var sb = new StringBuilder();

Expand All @@ -66,7 +64,7 @@ private static void WriteOpenApiExtensionMethodMapping(
.Append(_indent, 2)
.AppendLine("{");

MapWorkItemsForOpenApi(workItems, sb, v);
MapWorkItemsForOpenApi(workItems, sb, openApiVersion);

sb
.Append(_indent, 3)
Expand Down Expand Up @@ -139,21 +137,18 @@ private static void MapWorkItemsForOpenApi(IEnumerable<Item> workItems, StringBu
}
}

private static bool IsOpenApi1xReferenced(VogenKnownSymbols vogenKnownSymbols) => vogenKnownSymbols.OpenApiOptions is not null;
private static bool IsOpenApi2xReferenced(VogenKnownSymbols vogenKnownSymbols) => vogenKnownSymbols.JsonSchemaType is not null;

enum OpenApiVersionBeingUsed
{
None,
One,
TwoPlus
}

public static void WriteOpenApiSpecForMarkers(SourceProductionContext context,
List<VoWorkItem> workItems,
VogenKnownSymbols knownSymbols,
ImmutableArray<MarkerClassDefinition> markerClasses)
{
var openApiVersion = OpenApiSchemaUtils.DetermineOpenApiVersionBeingUsed(knownSymbols);

if (!OpenApiSchemaUtils.IsOpenApiOptionsReferenced(knownSymbols) || openApiVersion is OpenApiVersionBeingUsed.None)
{
return;
}

foreach (MarkerClassDefinition eachMarkerClass in markerClasses)
{
var matchingMarkers = eachMarkerClass.AttributeDefinitions.Where(a => a.Marker?.Kind == ConversionMarkerKind.OpenApi).ToList();
Expand All @@ -176,9 +171,8 @@ public static void WriteOpenApiSpecForMarkers(SourceProductionContext context,
WriteOpenApiExtensionMethodMapping(
context,
items,
knownSymbols,
$"MapVogenTypesIn{eachMarkerClass.MarkerClassSymbol.Name}",
OpenApiVersionBeingUsed.TwoPlus);
openApiVersion);
}
}
}
Loading
Loading