Skip to content

Update to .NET 9 and replace Swashbuckle/Swagger with ASP.NET Core OpenAPI generation #27

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Dec 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/dotnet.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: 8.x
dotnet-version: 9.x
- name: Restore dependencies
run: dotnet restore
- name: Build
Expand Down
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -397,11 +397,13 @@ FodyWeavers.xsd
# JetBrains Rider
*.sln.iml

appsettings.Development.json
appsettings.Development*.json
openapi/**/*.yml
openapi/**/*.json
plugin/**/*.json
plugin/**/*.yml
*.zip
.kiota/
BudgetTracker-DevTunnel.http
*.cer
start-tunnel.bat
4 changes: 2 additions & 2 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"request": "launch",
"preLaunchTask": "build",
// If you have changed target frameworks, make sure to update the program path.
"program": "${workspaceFolder}/api/bin/Debug/net8.0/BudgetTracker.dll",
"program": "${workspaceFolder}/api/bin/Debug/net9.0/BudgetTracker.dll",
"args": [],
"cwd": "${workspaceFolder}/api",
"stopAtEntry": false,
Expand All @@ -20,7 +20,7 @@
"serverReadyAction": {
"action": "openExternally",
"pattern": "\\bNow listening on:\\s+(https?://\\S+)",
"uriFormat": "%s/swagger"
"uriFormat": "%s/openapi/BudgetTracker.json"
},
"env": {
"ASPNETCORE_ENVIRONMENT": "Development"
Expand Down
13 changes: 13 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,24 @@
{
"cSpell.words": [
"authcomplete",
"cellspacing",
"devtunnel",
"MSRC",
"openapi",
"seealso",
"Swashbuckle",
"winget"
],
"cSpell.ignorePaths": [
"package-lock.json",
"node_modules",
"vscode-extension",
".git/{info,lfs,logs,refs,objects}/**",
".git/{index,*refs,*HEAD}",
".vscode",
".vscode-insiders",
".gitignore",
"*.csproj",
"examples/**"
]
}
20 changes: 20 additions & 0 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,14 @@
"label": "build",
"command": "dotnet",
"type": "process",
"options": {
"env": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"args": [
"build",
"--no-incremental",
"${workspaceFolder}/api/BudgetTracker.csproj",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary;ForceNoAlign"
Expand Down Expand Up @@ -36,6 +42,20 @@
"${workspaceFolder}/api/BudgetTracker.csproj"
],
"problemMatcher": "$msCompile"
},
{
"label": "gen-samples",
"detail": "Generate sample OpenAPI with placeholders",
"command": "dotnet",
"type": "process",
"args": [
"build",
"--no-incremental",
"${workspaceFolder}/api/BudgetTracker.csproj",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary;ForceNoAlign"
],
"problemMatcher": "$msCompile"
}
]
}
24 changes: 21 additions & 3 deletions api/BudgetTracker.csproj
Original file line number Diff line number Diff line change
@@ -1,26 +1,44 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net9.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<OpenApiGenerateDocuments>true</OpenApiGenerateDocuments>
<OpenApiGenerateDocumentsOnBuild>true</OpenApiGenerateDocumentsOnBuild>
</PropertyGroup>

<Choose>
<When Condition="$(ASPNETCORE_ENVIRONMENT) == Development">
<PropertyGroup>
<OpenApiDocumentsDirectory>../openapi</OpenApiDocumentsDirectory>
</PropertyGroup>
</When>
<When Condition="$(ASPNETCORE_ENVIRONMENT) == ''">
<PropertyGroup>
<OpenApiDocumentsDirectory>../examples/openapi</OpenApiDocumentsDirectory>
</PropertyGroup>
</When>
</Choose>

<ItemGroup>
<AdditionalFiles Include="$(MSBuildThisFileDirectory)stylecop.json" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="AdaptiveCards" Version="3.1.0" />
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.11" />
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="9.0.0" />
<PackageReference Include="Microsoft.Extensions.ApiDescription.Server" Version="9.0.0">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Microsoft.Identity.Web" Version="3.5.0" />
<PackageReference Include="Microsoft.Identity.Web.GraphServiceClient" Version="3.5.0" />
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.556">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.9.0" />
</ItemGroup>

</Project>
16 changes: 4 additions & 12 deletions api/Endpoints/BudgetsEndpoint.cs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using System.ComponentModel;
using BudgetTracker.Models;
using BudgetTracker.Services;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http.HttpResults;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Identity.Web.Resource;
using Microsoft.OpenApi.Any;

namespace BudgetTracker.Endpoints;

Expand All @@ -29,12 +29,6 @@ public static void Map(WebApplication app)
.WithName("GetBudgets")
.WithSummary("Get budgets based on budget name")
.WithDescription("Returns details including name and available funds of budgets, optionally filtered by budget name")
.WithOpenApi(operation =>
{
operation.Parameters[0].Description = "The name of the budget to retrieve";
operation.Parameters[0].Required = false;
return operation;
})
.RequireAuthorization();

app.MapPost(Endpoint, CreateBudget)
Expand All @@ -46,21 +40,19 @@ public static void Map(WebApplication app)
app.MapPost($"{Endpoint}/charge", ChargeBudget)
.WithName("ChargeBudget")
.WithSummary("Charge an amount to a budget")
.WithDescription("Charge an amount to a budget with a specified name. This removes the specified amount from the budget's available funds")
.WithOpenApi()
.WithDescription("Charge an amount to a budget with a specified name, removing the amount from available funds")
.RequireAuthorization();

app.MapPost($"{Endpoint}/extend", ExtendBudget)
.WithName("ExtendBudget")
.WithSummary("Add an amount to a budget")
.WithDescription("Add an amount to a budget with a specified name. This adds the specified amount to the budget's available funds")
.WithOpenApi()
.WithDescription("Add an amount to a budget with a specified name, adding the amount to available funds")
.RequireAuthorization();
}

private static Results<Ok<List<Budget>>, BadRequest<ApiResponse>> GetBudgets(
HttpContext context,
[FromQuery] string? budgetName,
[FromQuery][Description("The name of the budget to retrieve")] string? budgetName,
[FromServices] BudgetService budgetService,
[FromServices] ILogger<Program> logger)
{
Expand Down
30 changes: 6 additions & 24 deletions api/Endpoints/TransactionsEndpoint.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using System.Text.Json;
using System.ComponentModel;
using BudgetTracker.Models;
using BudgetTracker.Services;
using Microsoft.AspNetCore.Http.HttpResults;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Graph;
using Microsoft.Identity.Web.Resource;
using Microsoft.OpenApi.Any;

namespace BudgetTracker.Endpoints;

Expand All @@ -28,37 +27,20 @@ public static void Map(WebApplication app)
app.MapGet(Endpoint, GetTransactions)
.WithName("GetTransactions")
.WithSummary("Get transactions based on budget name or category")
.WithDescription("Returns details of transactions identified from filters like budget name or category. Multiple filters can be used in combination to refine the list of transactions returned")
.WithOpenApi(operation =>
{
operation.Parameters[0].Description = "The name of the budget to filter results on";
operation.Parameters[0].Required = false;
operation.Parameters[1].Description = "The name of the category to filter results on";
operation.Parameters[1].Required = false;
return operation;
})
.WithDescription("Returns details of transactions identified from filters like budget name or category")
.RequireAuthorization();

app.MapPost($"{Endpoint}/send", SendTransactionReport)
.WithName("SendTransactionReport")
.WithSummary("Send a transaction report to my email")
.WithDescription("Sends a transaction report via email, optionally filtered by budget.")
.WithOpenApi(operation =>
{
// Set this to false so Copilot will show an "always allow" option
operation.Extensions.Add("x-openai-isConsequential", new OpenApiBoolean(false));

operation.Parameters[0].Description = "The name of the budget to filter report on";
operation.Parameters[0].Required = false;
return operation;
})
.WithDescription("Sends a transaction report via email, optionally filtered by budget")
.RequireAuthorization();
}

private static Results<Ok<TransactionListResponse>, BadRequest<ApiResponse>> GetTransactions(
HttpContext context,
[FromQuery] string? budgetName,
[FromQuery] string? category,
[FromQuery][Description("The name of the budget to filter results on")] string? budgetName,
[FromQuery][Description("The name of the category to filter results on")] string? category,
[FromServices] BudgetService budgetService,
[FromServices] ILogger<Program> logger)
{
Expand All @@ -80,7 +62,7 @@ private static Results<Ok<TransactionListResponse>, BadRequest<ApiResponse>> Get

private static async Task<Results<Accepted<ApiResponse>, BadRequest<ApiResponse>>> SendTransactionReport(
HttpContext context,
[FromQuery] string? budgetName,
[FromQuery][Description("The name of the budget to filter report on")] string? budgetName,
[FromServices] BudgetService budgetService,
[FromServices] GraphServiceClient graphClient,
[FromServices] ILogger<Program> logger)
Expand Down
30 changes: 0 additions & 30 deletions api/Extensions/OpenApiExtensions.cs

This file was deleted.

4 changes: 3 additions & 1 deletion api/Models/ApiResponse.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using System.ComponentModel;

namespace BudgetTracker.Models;

/// <summary>
Expand All @@ -12,6 +14,6 @@ public class ApiResponse(string message)
/// Gets the response message.
/// </summary>
/// <example>1000 has been deducted from Contoso Copilot plugin project. The budget has 49000 remaining in available funds.</example>
/// <example>1000 has been added to Contoso Copilot plugin project. The budget has 51000 remaining in available funds.</example>
[Description("The response message")]
public string Message => message;
}
3 changes: 3 additions & 0 deletions api/Models/Budget.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using System.ComponentModel;
using System.ComponentModel.DataAnnotations;

namespace BudgetTracker.Models;
Expand All @@ -15,12 +16,14 @@ public class Budget
/// </summary>
/// <example>Contoso Copilot plugin project</example>
[Required]
[Description("The name of the budget")]
public string? Name { get; set; }

/// <summary>
/// Gets or sets the available funds in the budget.
/// </summary>
/// <example>50000</example>
[Required]
[Description("The available funds in the budget")]
public decimal AvailableFunds { get; set; }
}
6 changes: 6 additions & 0 deletions api/Models/Transaction.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using System.ComponentModel;
using System.ComponentModel.DataAnnotations;

namespace BudgetTracker.Models;
Expand All @@ -15,31 +16,36 @@ public class Transaction
/// </summary>
/// <example>Contoso Copilot plugin project</example>
[Required]
[Description("The name of the budget to adjust")]
public string? BudgetName { get; set; }

/// <summary>
/// Gets or sets the amount of the adjustment.
/// </summary>
/// <example>-5000</example>
[Required]
[Description("The amount of the adjustment")]
public decimal Amount { get; set; }

/// <summary>
/// Gets or sets a description for the change.
/// </summary>
/// <example>Purchase new laptops for team</example>
[Required]
[Description("The description for the change")]
public string? Description { get; set; }

/// <summary>
/// Gets or sets the expense category for charges against the budget.
/// </summary>
/// <example>hardware</example>
[Description("The expense category for charges against the budget")]
public string? ExpenseCategory { get; set; }

/// <summary>
/// Gets the JSONPath to the Adaptive Card template to use for rendering this transaction in an API plugin.
/// </summary>
[Description("The JSONPath to the Adaptive Card template to use for rendering this transaction in an API plugin")]
public string DisplayTemplate
{
get
Expand Down
Loading
Loading