Skip to content

Prep backend for .NET 10: replace obsolete hosting/crypto APIs - #4347

Merged
imnasnainaec merged 4 commits into
masterfrom
net10-prep-hosting-and-pbkdf2
Jul 28, 2026
Merged

Prep backend for .NET 10: replace obsolete hosting/crypto APIs#4347
imnasnainaec merged 4 commits into
masterfrom
net10-prep-hosting-and-pbkdf2

Conversation

@imnasnainaec

@imnasnainaec imnasnainaec commented Jul 27, 2026

Copy link
Copy Markdown
Collaborator

Summary

Prep work toward #4254 (Update .NET from 8 to 10). Replaces two APIs that are already obsolete-marked as of
.NET 9/10 and would fail the build outright once the TargetFramework is bumped, since the project builds with
TreatWarningsAsErrors=true. Neither replacement requires .NET 10, so landing them separately shrinks the scope of
the eventual TFM-bump PR.

No behavior changes: same password hashes, same service registrations, same middleware pipeline, same log messages.

Backend/Helper/PasswordHash.csSYSLIB0060

The Rfc2898DeriveBytes constructor is obsolete. Replaced with the static Rfc2898DeriveBytes.Pbkdf2(...) method,
passing the password as UTF-8 bytes. The old constructor also used UTF-8 internally, so existing stored hashes
continue to validate.

Backend/Program.csASPDEPR008

WebHost.CreateDefaultBuilder(...).UseStartup<Startup>() is obsolete. Main now uses WebApplicationBuilder
minimal hosting and invokes Startup's two methods directly:

var builder = WebApplication.CreateBuilder(args);
var startup = new Startup(builder.Configuration);
startup.ConfigureServices(builder.Services);
var app = builder.Build();
startup.Configure(app, app.Environment, app.Lifetime);
app.Run();

CreateWebHostBuilder is removed; it had no other callers.

Backend/Startup.cs

The old hosting model injected ILogger<Startup> into Startup's constructor, resolving it from the host's
internal service provider. Minimal hosting has no equivalent provider, and one can't be conjured before
builder.Build() without building a throwaway container. Rather than do that, each logger use now gets the real
application logger at the point where one is actually available:

  • Constructor takes only IConfiguration; the _logger field is gone.
  • Settings configuration (the only pre-Build() code path that logs) moves from
    services.Configure<Settings>(options => ...) to
    services.AddOptions<Settings>().Configure<ILogger<Startup>>((options, logger) => ...). The callback already ran
    lazily — on first IOptions<Startup.Settings> resolution, after the app is built — so this only changes where its
    logger comes from. CheckedEnvironmentVariable and CheckedEnvironmentVariablePositiveInt are now static and
    take the logger as a parameter.
  • Configure(...) resolves ILogger<Startup> from app.ApplicationServices and passes it to
    CreateAdminUser.
  • The JWT secret key check is the one message emitted during ConfigureServices, where no logging pipeline
    exists yet. It writes to stderr and then throws, as before.

Every consumer of Startup.Settings injects IOptions<Startup.Settings> (singleton), not IOptionsSnapshot or
IOptionsMonitor, so the configure callback still runs exactly once and the environment-variable warnings are not
repeated per scope.

Verification

  • dotnet build — clean, 0 warnings.
  • dotnet test — 1175 passed.
  • npm run fmt-backend-check — clean.
  • Manual run: the environment-variable messages and No admin user name provided, skipped admin creation appear as
    BackendFramework.Startup records through the application's logging pipeline; unsetting COMBINE_JWT_SECRET_KEY
    prints the stderr message before the exception. Neither path is covered by unit tests.

Created by Claude Sonnet 5 and Claude Opus 5


Devin: https://app.devin.ai/review/sillsdev/TheCombine/pull/4347


This change is Reviewable

Part of #4254. Migrates Program.cs from the obsolete WebHost/
IWebHostBuilder hosting model to WebApplicationBuilder, and replaces
the obsolete Rfc2898DeriveBytes constructor in PasswordHash with the
static Pbkdf2 method. Both APIs are already obsolete-marked under
.NET 9/10 (ASPDEPR008, SYSLIB0060) and TreatWarningsAsErrors turns
them into build failures once the TargetFramework is bumped. Neither
change depends on .NET 10 itself, so landing them now shrinks the
scope of the eventual TFM-bump PR.

Verified: builds clean on net8.0, full Backend.Tests suite passes
(1175/1175), including PasswordHashTests confirming byte-identical
hash output.
@coderabbitai

coderabbitai Bot commented Jul 27, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The PR updates PBKDF2 password derivation to use UTF-8 input with the static API, migrates application startup to WebApplication, and resolves startup logging through dependency injection during settings validation and admin-user initialization.

Changes

.NET runtime updates

Layer / File(s) Summary
PBKDF2 derivation update
Backend/Helper/PasswordHash.cs
Password hashing uses UTF-8 password bytes with Rfc2898DeriveBytes.Pbkdf2(...).
WebApplication startup migration
Backend/Program.cs
Startup creates and configures a WebApplication, then runs the application.
Startup logging and settings resolution
Backend/Startup.cs
Logging is resolved through dependency injection for environment validation, settings configuration, JWT validation, and admin-user initialization.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related issues

  • Issue 4254: Covers the WebApplication startup migration and replacement of the obsolete Rfc2898DeriveBytes constructor.

Sequence Diagram(s)

sequenceDiagram
  participant Main
  participant WebApplicationBuilder
  participant Startup
  participant WebApplication
  Main->>WebApplicationBuilder: CreateBuilder(args)
  Main->>Startup: ConfigureServices(builder.Services)
  WebApplicationBuilder->>WebApplication: Build()
  Main->>Startup: Configure(app, environment, lifetime)
  Startup->>Startup: Resolve ILogger<Startup>
  Main->>WebApplication: Run()
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: preparing the backend for .NET 10 by replacing obsolete hosting and crypto APIs.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch net10-prep-hosting-and-pbkdf2

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.

@imnasnainaec
imnasnainaec marked this pull request as ready for review July 27, 2026 18:55
@codecov

codecov Bot commented Jul 27, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 87.22%. Comparing base (634121d) to head (a6630f3).
⚠️ Report is 2 commits behind head on master.

Additional details and impacted files
@@             Coverage Diff             @@
##           master    #4347       +/-   ##
===========================================
+ Coverage   75.96%   87.22%   +11.26%     
===========================================
  Files         305       57      -248     
  Lines       11384     5081     -6303     
  Branches     1411      617      -794     
===========================================
- Hits         8648     4432     -4216     
+ Misses       2332      506     -1826     
+ Partials      404      143      -261     
Flag Coverage Δ
backend 87.22% <100.00%> (ø)
frontend ?

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@Backend/Program.cs`:
- Around line 14-16: Update the startup logger initialization around
LoggerFactory.Create and Startup so it reuses the WebApplicationBuilder logging
pipeline and providers instead of creating a separate console-only factory. Pass
the shared ILoggerFactory-derived Startup logger while preserving the existing
configuration and provider registrations from builder.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: b05cc5c3-91b3-4bab-a41c-3f76e3fc8c58

📥 Commits

Reviewing files that changed from the base of the PR and between 634121d and 4a1040f.

📒 Files selected for processing (2)
  • Backend/Helper/PasswordHash.cs
  • Backend/Program.cs

Comment thread Backend/Program.cs Outdated
@imnasnainaec
imnasnainaec marked this pull request as draft July 27, 2026 19:29
Building the startup-time ILoggerFactory with LoggerFactory.Create
only wired up Console, so Startup's early log calls (JWT secret,
CAPTCHA/email config checks) silently skipped the Debug/EventSource/
EventLog providers that WebApplicationBuilder registers by default
for the rest of the app. Build it instead from a copy of
WebApplicationBuilder's own service collection, so it shares the
exact same provider configuration.
CreateStartupLoggerFactory discarded the ServiceProvider it built
after pulling out the ILoggerFactory, so the intermediate provider
(and any disposable singletons it created) was never disposed. Now
CreateStartupServiceProvider returns the provider itself, scoped to a
using block that ends right after Startup.Configure returns, so
cleanup happens deterministically before app.Run() rather than being
left to GC.
@imnasnainaec
imnasnainaec marked this pull request as ready for review July 27, 2026 19:54

@hahn-kev hahn-kev left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

It looks good, though I do have a suggestion.

Comment thread Backend/Program.cs Outdated
Startup's constructor no longer takes ILogger<Startup>, so Program no
longer needs to build a throwaway service provider just to obtain one
before the app exists.

- Settings configuration uses AddOptions<Settings>().Configure<T>() so
  the environment-variable helpers get the real app logger, injected.
- Configure() resolves its logger from app.ApplicationServices.
- The JWT secret check writes to stderr before throwing; no logging
  pipeline exists at that point in ConfigureServices.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@imnasnainaec imnasnainaec self-assigned this Jul 28, 2026
Comment thread Backend/Startup.cs Dismissed
Comment thread Backend/Startup.cs Dismissed
Comment thread Backend/Startup.cs Dismissed
Comment thread Backend/Startup.cs Dismissed
Comment thread Backend/Startup.cs Dismissed
Comment thread Backend/Startup.cs Dismissed
Comment thread Backend/Startup.cs Dismissed
Comment thread Backend/Startup.cs Dismissed
@imnasnainaec
imnasnainaec requested a review from hahn-kev July 28, 2026 13:38

@imnasnainaec imnasnainaec left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

@imnasnainaec reviewed all commit messages, resolved 1 discussion, and dismissed @hahn-kev from a discussion.
Reviewable status: 0 of 3 files reviewed, all discussions resolved (waiting on hahn-kev).

@jasonleenaylor jasonleenaylor left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

On the strength of Kevin's approval :lgtm:

@jasonleenaylor reviewed 3 files and all commit messages, and made 1 comment.
Reviewable status: :shipit: complete! all files reviewed, all discussions resolved (waiting on hahn-kev).

@imnasnainaec
imnasnainaec enabled auto-merge (squash) July 28, 2026 18:19
@imnasnainaec
imnasnainaec merged commit 8af1d5e into master Jul 28, 2026
16 checks passed
@imnasnainaec
imnasnainaec deleted the net10-prep-hosting-and-pbkdf2 branch July 28, 2026 18:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants