Skip to content

Conversation

@hhvrc
Copy link
Contributor

@hhvrc hhvrc commented Nov 6, 2025

To be merged after .NET 10 release date, November 11th 2025
closes #185

@hhvrc hhvrc requested a review from LucHeart November 6, 2025 20:58
@hhvrc hhvrc self-assigned this Nov 6, 2025
@hhvrc hhvrc added enhancement New feature or request .NET Pull requests that update .NET code labels Nov 6, 2025
Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@hhvrc
Copy link
Contributor Author

hhvrc commented Nov 11, 2025

Currently waiting on Npgsql.EntityFrameworkCore.PostgreSQL to release the .NET 10 version
This will be done in npgsql/npgsql#6311

@hhvrc hhvrc marked this pull request as draft November 11, 2025 21:31
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR upgrades the project from .NET 9 to .NET 10, scheduled for release after November 11th, 2025. The upgrade includes updating the SDK, runtime, packages, and migrating from Swashbuckle/Swagger to the native Microsoft.AspNetCore.OpenApi implementation.

  • Updated .NET SDK and runtime to version 10.0
  • Migrated from Swashbuckle to Microsoft.AspNetCore.OpenApi with new document generation and Scalar API viewer integration
  • Updated NuGet packages to their .NET 10 compatible versions
  • Applied code refactorings leveraging C# 13 features (field keyword) and API improvements

Reviewed changes

Copilot reviewed 43 out of 43 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
global.json Updated SDK version to 10.0.0 and added Microsoft.Testing.Platform test runner configuration
docker/*.Dockerfile Updated base images from dotnet 9.0-alpine to 10.0-alpine
Directory.Packages.props Updated all Microsoft packages and dependencies to version 10.0.0, removed Swashbuckle package
Directory.Build.props Updated target framework to net10.0 and added OpenAPI interceptors namespace
LiveControlGateway/Program.cs, Cron/Program.cs, API/Program.cs Replaced AddSwaggerExt with AddOpenApiExt and updated namespace imports
LiveControlGateway/Controllers/HubControllerBase.cs Refactored property to use C# 13 field keyword for cleaner auto-property backing field access
Common/Utils/TrustedProxiesFetcher.cs Simplified lambda expression removing unnecessary parameter specification
Common/Utils/ConfigureSwaggerOptions.cs Removed - functionality migrated to new OpenAPI implementation
Common/Swagger/* Removed Swashbuckle-specific files including SwaggerGenExtensions.cs and AttributeFilter.cs
Common/OpenAPI/OpenApiExtensions.cs New OpenAPI document configuration with output caching and custom operation ID generation
Common/OpenAPI/DocumentDefaults.cs New document transformer defining API info, servers, and security schemes
Common/OpenShockServiceHelper.cs Updated API versioning configuration for compatibility with new OpenAPI generation
Common/OpenShockMiddlewareHelper.cs Replaced UseSwagger with MapOpenApi, updated Scalar viewer configuration, changed KnownNetworks to KnownIPNetworks
Common/Services/Session/SessionService.cs Changed ToArrayAsync to ToListAsync and updated Length to Count for consistency
Common/Hubs/UserHub.cs Changed ToArrayAsync to ToListAsync for consistency with EF Core best practices
Common/DataAnnotations/*.cs Removed IParameterAttribute interface implementations and OpenAPI-specific Apply methods
Common/DataAnnotations/OpenApiSchemas.cs Removed - schemas now handled through native OpenAPI mechanisms
Common/DataAnnotations/Interfaces/* Removed custom attribute interfaces as they're replaced by native OpenAPI extensibility
Common/Common.csproj Added Microsoft.AspNetCore.OpenApi package, removed Swashbuckle.AspNetCore.SwaggerGen
API/Services/LCGNodeProvisioner/LCGNodeProvisioner.cs Changed ToArrayAsync to ToListAsync and Length to Count
API/Controller/Sessions/ListSessions.cs Refactored to return IAsyncEnumerable directly with Select instead of manual yield
API/Controller/OAuth/_ApiController.cs Added EndpointGroupName attribute for API grouping, consolidated ApiVersion attribute
API/Controller/OAuth/*.cs Removed ApiExplorerSettings(IgnoreApi = true) to include OAuth endpoints in OpenAPI docs
API/Controller/Device/Pair.cs Split endpoint into two methods (Pair and PairDeprecated) with separate EndpointName attributes and shared PairInternal helper
API/Controller/Admin/_ApiController.cs Added EndpointGroupName attribute for admin API grouping
API/Controller/Admin/GetOnlineDevices.cs Changed ToArrayAsync to ToListAsync
API.IntegrationTests/Tests/LcgAssignmentTests.cs Changed ToArrayAsync to ToListAsync in test cleanup
.github/workflows/*.yml Updated DOTNET_VERSION to 10.x.x and 10.0.x, modified test command syntax

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 21 to 71
using (var tempProvider = builder.Services.BuildServiceProvider())
{
var apiVersionProvider = tempProvider.GetRequiredService<IApiVersionDescriptionProvider>();

// Configure OpenAPI for each API version
foreach (var description in apiVersionProvider.ApiVersionDescriptions)
{
builder.Services.AddOpenApi(description.GroupName, options =>
{
options.OpenApiVersion = OpenApiSpecVersion.OpenApi3_1;
options.AddDocumentTransformer(DocumentDefaults.GetDocumentTransformer(
version: description.ApiVersion.ToString()));
options.CreateSchemaReferenceId = (type) =>
{
var defaultName = type.Type.Name;
var cleanName = defaultName
.Replace("[]", "Array")
.Replace("`1", "Of")
.Replace("`2", "OfTwo");
return cleanName;
};
options.AddOperationTransformer((operation, context, cancellationToken) =>
{
var actionDescriptor = context.Description.ActionDescriptor;

// Use endpoint name if available
var endpointName = actionDescriptor.EndpointMetadata
.OfType<EndpointNameMetadata>()
.FirstOrDefault()?.EndpointName;

if (!string.IsNullOrEmpty(endpointName))
{
operation.OperationId = endpointName;
return Task.CompletedTask;
}

// For controllers
var controller = actionDescriptor.RouteValues.TryGetValue("controller", out var ctrl) ? ctrl : null;
var action = actionDescriptor.RouteValues.TryGetValue("action", out var act) ? act : null;

if (!string.IsNullOrEmpty(controller) && !string.IsNullOrEmpty(action))
{
operation.OperationId = $"{controller}{action}";
}

return Task.CompletedTask;
});
});
}
}

Copy link

Copilot AI Dec 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Building a temporary service provider within the service configuration can lead to issues. This pattern captures services at configuration time and may not include all registered services or properly dispose of them. Consider using IConfigureOptions pattern or deferring this logic to application startup where the service provider is fully built.

Suggested change
using (var tempProvider = builder.Services.BuildServiceProvider())
{
var apiVersionProvider = tempProvider.GetRequiredService<IApiVersionDescriptionProvider>();
// Configure OpenAPI for each API version
foreach (var description in apiVersionProvider.ApiVersionDescriptions)
{
builder.Services.AddOpenApi(description.GroupName, options =>
{
options.OpenApiVersion = OpenApiSpecVersion.OpenApi3_1;
options.AddDocumentTransformer(DocumentDefaults.GetDocumentTransformer(
version: description.ApiVersion.ToString()));
options.CreateSchemaReferenceId = (type) =>
{
var defaultName = type.Type.Name;
var cleanName = defaultName
.Replace("[]", "Array")
.Replace("`1", "Of")
.Replace("`2", "OfTwo");
return cleanName;
};
options.AddOperationTransformer((operation, context, cancellationToken) =>
{
var actionDescriptor = context.Description.ActionDescriptor;
// Use endpoint name if available
var endpointName = actionDescriptor.EndpointMetadata
.OfType<EndpointNameMetadata>()
.FirstOrDefault()?.EndpointName;
if (!string.IsNullOrEmpty(endpointName))
{
operation.OperationId = endpointName;
return Task.CompletedTask;
}
// For controllers
var controller = actionDescriptor.RouteValues.TryGetValue("controller", out var ctrl) ? ctrl : null;
var action = actionDescriptor.RouteValues.TryGetValue("action", out var act) ? act : null;
if (!string.IsNullOrEmpty(controller) && !string.IsNullOrEmpty(action))
{
operation.OperationId = $"{controller}{action}";
}
return Task.CompletedTask;
});
});
}
}
// NOTE:
// The previous implementation built a temporary service provider here to resolve
// IApiVersionDescriptionProvider and register an OpenAPI document per API version.
// Building a temporary provider during service registration is an anti-pattern and
// was flagged by static analysis. Per-version OpenAPI document registration should
// be performed in a component that receives IApiVersionDescriptionProvider via DI
// (for example, using IConfigureOptions in another part of the application) rather
// than by calling BuildServiceProvider() on builder.Services.

Copilot uses AI. Check for mistakes.
run: |
set -euo pipefail
dotnet test -c Release ${{ matrix.project }}
dotnet test -c Release --project ${{ matrix.project }}
Copy link

Copilot AI Dec 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The --project flag is incorrect syntax for dotnet test. The correct syntax is to pass the project path directly without a flag, as it was before. Change back to: dotnet test -c Release ${{ matrix.project }}

Suggested change
dotnet test -c Release --project ${{ matrix.project }}
dotnet test -c Release ${{ matrix.project }}

Copilot uses AI. Check for mistakes.
Comment on lines +10 to +15
var assembly = typeof(TProgram).Assembly;

string assemblyName = assembly
.GetName()
.Name ?? throw new NullReferenceException("Assembly name");

Copy link

Copilot AI Dec 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This assignment to assemblyName is useless, since its value is never read.

Suggested change
var assembly = typeof(TProgram).Assembly;
string assemblyName = assembly
.GetName()
.Name ?? throw new NullReferenceException("Assembly name");

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request .NET Pull requests that update .NET code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Remove Swagger (replace with Microsoft OpenAPI)

4 participants