Skip to content

Conversation

@yilmaztayfun
Copy link
Contributor

@yilmaztayfun yilmaztayfun commented Jan 19, 2026

Summary by Sourcery

Upgrade the framework, infrastructure, and tooling to target .NET 10 and align supporting configuration and integrations with the new runtime and library patterns.

Bug Fixes:

  • Ensure keyed service resolution uses the IKeyedServiceProvider interface for cached service retrieval.
  • Fix Redis cache deserialization by explicitly casting cached values to string before JSON deserialization and disabling TTL preservation on cache set operations to enforce new expiry settings.

Enhancements:

  • Refactor Swagger and API versioning integration to use the ConfigureOptions pattern for versioned Swagger document generation.
  • Update AutoMapper registration to use the newer overload supporting additional configuration.
  • Replace the legacy .sln solution with a .slnx-based solution across build, analysis, and tooling commands.
  • Refresh README technology badge to reflect .NET 10 support.

Build:

  • Update global.json and SDK/tooling configuration to use .NET 10 SDK.
  • Adjust GitHub Actions workflows to build and publish with .NET 10 and the new .slnx solution file.

CI:

  • Update Sonar analysis workflow to build the new .slnx solution file.

Migrated all projects to target .NET 10.0, updated NuGet package versions across the solution, and replaced the legacy .sln file with a new .slnx format. CI/CD workflows and documentation were updated to reflect .NET 10.0 usage. Improved Swagger versioning configuration and fixed minor issues in Redis cache and AutoMapper registration.
Replaces Expiration.KeepTtl with the actual expiry value and sets keepTtl to false in StringSetAsync. This ensures that the cache entry uses the intended expiration time instead of keeping the previous TTL.
Upgrade to .NET 10 and update dependencies
@yilmaztayfun yilmaztayfun self-assigned this Jan 19, 2026
@yilmaztayfun yilmaztayfun requested review from a team as code owners January 19, 2026 20:17
@coderabbitai
Copy link

coderabbitai bot commented Jan 19, 2026

Warning

Rate limit exceeded

@yilmaztayfun has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 13 minutes and 32 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 309c8ae and 43ac246.

📒 Files selected for processing (22)
  • .github/workflows/check-sonar.yml
  • .github/workflows/publish-nuget.yml
  • Directory.Packages.props
  • README.md
  • common.props
  • framework/BBT.Aether.sln
  • framework/BBT.Aether.slnx
  • framework/src/BBT.Aether.Abstractions/BBT.Aether.Abstractions.csproj
  • framework/src/BBT.Aether.Application/BBT.Aether.Application.csproj
  • framework/src/BBT.Aether.AspNetCore/BBT.Aether.AspNetCore.csproj
  • framework/src/BBT.Aether.AspNetCore/Microsoft/Extensions/DependencyInjection/AetherApiVersioningServiceCollectionExtensions.cs
  • framework/src/BBT.Aether.Aspects/BBT.Aether.Aspects.csproj
  • framework/src/BBT.Aether.Cli/BBT.Aether.Cli.csproj
  • framework/src/BBT.Aether.Core/BBT.Aether.Core.csproj
  • framework/src/BBT.Aether.Core/BBT/Aether/DependencyInjection/CachedServiceProviderBase.cs
  • framework/src/BBT.Aether.Domain/BBT.Aether.Domain.csproj
  • framework/src/BBT.Aether.HttpClient/BBT.Aether.HttpClient.csproj
  • framework/src/BBT.Aether.Infrastructure/BBT.Aether.Infrastructure.csproj
  • framework/src/BBT.Aether.Infrastructure/BBT/Aether/DistributedCache/Redis/RedisDistributedCacheService.cs
  • framework/src/BBT.Aether.Infrastructure/Microsoft/Extensions/DependencyInjection/AetherMapperServiceCollectionExtensions.cs
  • framework/src/BBT.Aether.TestBase/BBT.Aether.TestBase.csproj
  • global.json

Note

.coderabbit.yaml has unrecognized properties

CodeRabbit is using all valid settings from your configuration. Unrecognized properties (listed below) have been ignored and may indicate typos or deprecated fields that can be removed.

⚠️ Parsing warnings (1)
Validation error: Unrecognized key(s) in object: 'review'
⚙️ Configuration instructions
  • Please see the configuration documentation for more information.
  • You can also validate your configuration using the online YAML validator.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch master

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@yilmaztayfun yilmaztayfun changed the title net10 upgrated net10 upgraded Jan 19, 2026
@yilmaztayfun yilmaztayfun merged commit b387f57 into release-v1.0 Jan 19, 2026
5 checks passed
@gemini-code-assist
Copy link

Summary of Changes

Hello @yilmaztayfun, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request performs a significant upgrade of the project's entire dependency stack to align with .NET 10.0. This comprehensive update ensures the codebase leverages the latest framework features, performance enhancements, and security improvements. The changes encompass updating the target framework for all core projects, bumping versions for a wide array of third-party NuGet packages, and adapting existing code to new API conventions introduced in the updated libraries. The modernization also includes a shift to a new solution file format, streamlining project management.

Highlights

  • .NET 10.0 Upgrade: The project's target framework has been updated from .NET 9.0 to .NET 10.0 across all core projects, including Abstractions, Application, ASP.NET Core, Aspects, CLI, Core, Domain, HTTP Client, Infrastructure, and TestBase.
  • Extensive Package Version Updates: Numerous NuGet packages have been upgraded to their latest compatible versions for .NET 10.0. This includes critical updates for Autofac, AutoMapper, Dapr, JetBrains.Annotations, Microsoft.AspNetCore., Microsoft.EntityFrameworkCore., Microsoft.Extensions.*, OpenTelemetry, PostSharp, Serilog, StackExchange.Redis, Swashbuckle.AspNetCore, and Npgsql.EntityFrameworkCore.PostgreSQL.
  • Solution File Modernization: The traditional Visual Studio solution file (.sln) has been removed and replaced with a new XML-based solution file (.slnx), which lists all project files under the src folder.
  • API Usage Adjustments: Minor code adjustments were made to accommodate API changes in updated libraries. This includes explicit casting for keyed service resolution in CachedServiceProviderBase, a new pattern for AutoMapper service registration, and refactoring of Swagger generation to use the IConfigureOptions<SwaggerGenOptions> pattern.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Ignored Files
  • Ignored by pattern: .github/workflows/** (2)
    • .github/workflows/check-sonar.yml
    • .github/workflows/publish-nuget.yml
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request effectively upgrades the project to .NET 10, which is a significant undertaking. The changes include updating numerous package versions, modifying target frameworks in project files, and adapting the code to breaking changes from the updated dependencies. The refactoring of the Swagger/ApiVersioning configuration to use the IConfigureOptions pattern is a notable improvement, as is the switch to the modern .slnx solution file format. I have one suggestion regarding the suppression of new warnings.

<LangVersion>latest</LangVersion>
<Version>1.0.0</Version>
<NoWarn>$(NoWarn);CS1591;CS0436</NoWarn>
<NoWarn>$(NoWarn);CS1591;CS0436;DAPR_JOBS;DAPR_DISTRIBUTEDLOCK</NoWarn>

Choose a reason for hiding this comment

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

medium

Two new warning codes, DAPR_JOBS and DAPR_DISTRIBUTEDLOCK, have been added to the suppressed warnings list. Suppressing warnings can hide potential issues and make maintenance harder. Please consider addressing these warnings instead of suppressing them. If suppression is necessary (e.g., for known issues or false positives), please add an XML comment above this line explaining the reason for future reference.

@sourcery-ai
Copy link

sourcery-ai bot commented Jan 19, 2026

Reviewer's Guide

.NET 10 upgrade across the repo, including SDK/tooling updates, migration from .sln to .slnx, adjustments for new ASP.NET/DI/Swagger APIs, safer Redis cache serialization, and updated AutoMapper registration.

Sequence diagram for Swagger configuration with API versioning

sequenceDiagram
    participant HostBuilder
    participant ServiceCollection
    participant SwaggerGen
    participant ConfigureSwaggerOptions
    participant ApiVersionDescriptionProvider

    HostBuilder->>ServiceCollection: AddAetherApiVersioning(apiTitle)
    ServiceCollection->>ServiceCollection: AddApiVersioning()
    ServiceCollection->>SwaggerGen: AddSwaggerGen()
    ServiceCollection->>ServiceCollection: AddTransient IConfigureOptions_SwaggerGenOptions
    ServiceCollection->>ConfigureSwaggerOptions: Create instance(provider, apiTitle)

    HostBuilder->>SwaggerGen: Resolve SwaggerGenOptions
    SwaggerGen->>ConfigureSwaggerOptions: Configure(options)
    ConfigureSwaggerOptions->>ApiVersionDescriptionProvider: get ApiVersionDescriptions
    loop For each ApiVersionDescription
        ConfigureSwaggerOptions->>SwaggerGen: options.SwaggerDoc(groupName, OpenApiInfo)
    end
Loading

Updated class diagram for Swagger configuration and DI integration

classDiagram
    class AetherApiVersioningServiceCollectionExtensions {
        +IServiceCollection AddAetherApiVersioning(services, apiTitle)
    }

    class ConfigureSwaggerOptions {
        -IApiVersionDescriptionProvider _provider
        -string _apiTitle
        +ConfigureSwaggerOptions(IApiVersionDescriptionProvider provider, string apiTitle)
        +void Configure(SwaggerGenOptions options)
    }

    class IServiceCollection {
        <<interface>>
        +IServiceCollection AddApiVersioning()
        +IServiceCollection AddSwaggerGen()
        +IServiceCollection AddTransient(serviceType, implementationFactory)
    }

    class IApiVersionDescriptionProvider {
        <<interface>>
        +IReadOnlyList ApiVersionDescriptions
    }

    class SwaggerGenOptions {
        +void SwaggerDoc(name, OpenApiInfo info)
    }

    class OpenApiInfo {
        +string Title
        +string Version
        +string Description
    }

    AetherApiVersioningServiceCollectionExtensions ..> IServiceCollection : extends
    AetherApiVersioningServiceCollectionExtensions ..> ConfigureSwaggerOptions : registers
    ConfigureSwaggerOptions ..|> IConfigureOptions_SwaggerGenOptions
    ConfigureSwaggerOptions --> IApiVersionDescriptionProvider : uses
    ConfigureSwaggerOptions --> SwaggerGenOptions : configures
    SwaggerGenOptions --> OpenApiInfo : creates
Loading

File-Level Changes

Change Details Files
Refactor API versioning and Swagger registration to use ConfigureOptions pattern compatible with newer ASP.NET/Swashbuckle versions.
  • Replace direct SwaggerGen configuration in AddAetherApiVersioning with AddSwaggerGen plus a transient IConfigureOptions registration.
  • Introduce ConfigureSwaggerOptions class that uses IApiVersionDescriptionProvider to register Swagger docs per API version.
  • Update usings to include Microsoft.Extensions.Options, Microsoft.OpenApi, and Swashbuckle.AspNetCore.SwaggerGen while removing the old Microsoft.OpenApi.Models direct usage.
framework/src/BBT.Aether.AspNetCore/Microsoft/Extensions/DependencyInjection/AetherApiVersioningServiceCollectionExtensions.cs
Adjust AutoMapper registration to the newer AddAutoMapper overload while preserving assembly scanning.
  • Change AddAetherAutoMapperMapper to call AddAutoMapper with a configuration callback plus assemblies array instead of only assemblies.
  • Keep existing AutoMapper-based IObjectMapper registrations unchanged.
framework/src/BBT.Aether.Infrastructure/Microsoft/Extensions/DependencyInjection/AetherMapperServiceCollectionExtensions.cs
Update keyed service resolution to use the IKeyedServiceProvider interface for compatibility with newer DI APIs.
  • Replace ServiceProvider.GetKeyedService/GetRequiredKeyedService calls with casts to IKeyedServiceProvider followed by interface method calls.
  • Retain existing caching via ConcurrentDictionary and Lazy to avoid duplicate resolutions.
framework/src/BBT.Aether.Core/BBT/Aether/DependencyInjection/CachedServiceProviderBase.cs
Harden Redis distributed cache serialization/deserialization for new StackExchange.Redis behaviors and TTL handling.
  • Cast cached values to string when deserializing JSON to ensure correct type for JsonSerializer.Deserialize.
  • Explicitly pass keepTtl: false to StringSetAsync so new values reset TTL instead of inheriting existing TTL.
framework/src/BBT.Aether.Infrastructure/BBT/Aether/DistributedCache/Redis/RedisDistributedCacheService.cs
Upgrade repository to .NET 10 SDK and migrate solutions and pipelines to .slnx format.
  • Update GitHub workflows to use .NET SDK 10.0.x and operate on BBT.Aether.slnx instead of .sln.
  • Change global.json SDK version from 9.0.101 to 10.0.101.
  • Replace the old BBT.Aether.sln with a new BBT.Aether.slnx solution file and update Sonar build workflow to build the .slnx.
  • Adjust project- and package-related props/csproj files (per diff) to align with .NET 10 requirements.
.github/workflows/publish-nuget.yml
.github/workflows/check-sonar.yml
global.json
framework/BBT.Aether.slnx
framework/BBT.Aether.sln
Directory.Packages.props
common.props
framework/src/BBT.Aether.Abstractions/BBT.Aether.Abstractions.csproj
framework/src/BBT.Aether.Application/BBT.Aether.Application.csproj
framework/src/BBT.Aether.AspNetCore/BBT.Aether.AspNetCore.csproj
framework/src/BBT.Aether.Aspects/BBT.Aether.Aspects.csproj
framework/src/BBT.Aether.Cli/BBT.Aether.Cli.csproj
framework/src/BBT.Aether.Core/BBT.Aether.Core.csproj
framework/src/BBT.Aether.Domain/BBT.Aether.Domain.csproj
framework/src/BBT.Aether.HttpClient/BBT.Aether.HttpClient.csproj
framework/src/BBT.Aether.Infrastructure/BBT.Aether.Infrastructure.csproj
framework/src/BBT.Aether.TestBase/BBT.Aether.TestBase.csproj
Update documentation to reflect .NET 10 as the target platform.
  • Change README badge to advertise .NET 10.0 instead of 8.0/9.0.
README.md

Possibly linked issues

  • #: PR updates SDK, solutions, workflows, and code patterns required for migrating the project to .NET 10 LTS.

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@sonarqubecloud
Copy link

Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey - I've found 2 issues, and left some high level feedback:

  • In CachedServiceProviderBase, casting ServiceProvider to IKeyedServiceProvider introduces a hard dependency on a specific provider implementation and can cause InvalidCastException; consider keeping the extension-based calls or guarding the cast with a type check/fallback.
  • In RedisDistributedCacheService, the explicit (string)cachedValue! cast assumes all cached values are stored as strings; if any callers store non-string data, this will now fail—consider using RedisValue’s byte[] conversion or validating the type before casting.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `CachedServiceProviderBase`, casting `ServiceProvider` to `IKeyedServiceProvider` introduces a hard dependency on a specific provider implementation and can cause `InvalidCastException`; consider keeping the extension-based calls or guarding the cast with a type check/fallback.
- In `RedisDistributedCacheService`, the explicit `(string)cachedValue!` cast assumes all cached values are stored as strings; if any callers store non-string data, this will now fail—consider using `RedisValue`’s byte[] conversion or validating the type before casting.

## Individual Comments

### Comment 1
<location> `framework/src/BBT.Aether.Core/BBT/Aether/DependencyInjection/CachedServiceProviderBase.cs:54` </location>
<code_context>
         return CachedServices.GetOrAdd(
             new ServiceIdentifier(serviceKey, serviceType),
-            _ => new Lazy<object?>(() =>  ServiceProvider.GetKeyedService(serviceType, serviceKey))
+            _ => new Lazy<object?>(() => ((IKeyedServiceProvider)ServiceProvider).GetKeyedService(serviceType, serviceKey))
         ).Value;
     }
</code_context>

<issue_to_address>
**issue (bug_risk):** Casting ServiceProvider to IKeyedServiceProvider may cause runtime failures with non-core DI containers.

This cast assumes `ServiceProvider` implements `IKeyedServiceProvider`; if an app uses a different container or a wrapper that doesn't, you'll get an `InvalidCastException` at runtime. Consider using a safer pattern (e.g., `ServiceProvider as IKeyedServiceProvider` with a fallback) or introducing an abstraction that alternative DI providers can implement.
</issue_to_address>

### Comment 2
<location> `framework/src/BBT.Aether.Core/BBT/Aether/DependencyInjection/CachedServiceProviderBase.cs:62` </location>
<code_context>
         return CachedServices.GetOrAdd(
             new ServiceIdentifier(serviceKey, serviceType),
-            _ => new Lazy<object?>(() =>  ServiceProvider.GetRequiredKeyedService(serviceType, serviceKey))
+            _ => new Lazy<object?>(() => ((IKeyedServiceProvider)ServiceProvider).GetRequiredKeyedService(serviceType, serviceKey))
         ).Value!;
     }
</code_context>

<issue_to_address>
**issue (bug_risk):** Same casting concern for GetRequiredKeyedService can lead to unexpected InvalidCastException.

This cast will throw if `ServiceProvider` doesn’t implement `IKeyedServiceProvider`, causing an `InvalidCastException` instead of the expected “missing keyed service” error. It’d be better to resolve keyed services via the same abstraction/extension pattern used elsewhere so behavior stays consistent across different containers.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

return CachedServices.GetOrAdd(
new ServiceIdentifier(serviceKey, serviceType),
_ => new Lazy<object?>(() => ServiceProvider.GetKeyedService(serviceType, serviceKey))
_ => new Lazy<object?>(() => ((IKeyedServiceProvider)ServiceProvider).GetKeyedService(serviceType, serviceKey))
Copy link

Choose a reason for hiding this comment

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

issue (bug_risk): Casting ServiceProvider to IKeyedServiceProvider may cause runtime failures with non-core DI containers.

This cast assumes ServiceProvider implements IKeyedServiceProvider; if an app uses a different container or a wrapper that doesn't, you'll get an InvalidCastException at runtime. Consider using a safer pattern (e.g., ServiceProvider as IKeyedServiceProvider with a fallback) or introducing an abstraction that alternative DI providers can implement.

return CachedServices.GetOrAdd(
new ServiceIdentifier(serviceKey, serviceType),
_ => new Lazy<object?>(() => ServiceProvider.GetRequiredKeyedService(serviceType, serviceKey))
_ => new Lazy<object?>(() => ((IKeyedServiceProvider)ServiceProvider).GetRequiredKeyedService(serviceType, serviceKey))
Copy link

Choose a reason for hiding this comment

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

issue (bug_risk): Same casting concern for GetRequiredKeyedService can lead to unexpected InvalidCastException.

This cast will throw if ServiceProvider doesn’t implement IKeyedServiceProvider, causing an InvalidCastException instead of the expected “missing keyed service” error. It’d be better to resolve keyed services via the same abstraction/extension pattern used elsewhere so behavior stays consistent across different containers.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants