Skip to content

Retarget all managed projects to .NET 10 (net10.0-windows10.0.17763.0)#1947

Draft
tyrielv wants to merge 6 commits intomicrosoft:masterfrom
tyrielv:tyrielv/net10-tfm-retarget
Draft

Retarget all managed projects to .NET 10 (net10.0-windows10.0.17763.0)#1947
tyrielv wants to merge 6 commits intomicrosoft:masterfrom
tyrielv:tyrielv/net10-tfm-retarget

Conversation

@tyrielv
Copy link
Copy Markdown
Contributor

@tyrielv tyrielv commented Apr 16, 2026

Phase 3 of the .NET 10 migration: TFM retarget, API migrations, and build/CI updates consolidated into a single PR.

Foundation:

  • Pin .NET 10 SDK in global.json (10.0.100 with latestFeature rollback)
  • Centralize TargetFramework in Directory.Build.props
  • Bump default dev version to 0.3.0.1 (official builds use 2.0.x.x)
  • Update MSBuild SDK versions (Traversal 4.1.0, NoTargets 3.7.0)
  • Update CI to .NET 10 SDK and windows-2025 runner

Package updates:

  • Microsoft.Data.Sqlite 2.2.4 -> 9.0.4
  • Microsoft.Build.* 16.0.461 -> 17.12.6
  • Microsoft.Windows.ProjFS 1.1.19156.1 -> 2.1.0
  • System.ServiceProcess.ServiceController 4.5.0 -> 9.0.4
  • Add System.Diagnostics.EventLog, System.Management, System.IO.Pipes.AccessControl
  • Remove GVFS.ProjFS package (ProjFS is now a Windows OS feature)
  • Replace CommandLineParser and Newtonsoft.Json stale references

API migrations:

  • HttpUtility.UrlEncode -> WebUtility.UrlEncode (OrgInfoApiClient)
  • Assembly.Location -> Environment.ProcessPath (ProcessHelper, HooksInstaller)
  • NamedPipeServerStream ctor -> NamedPipeServerStreamAcl.Create (WindowsPlatform)
  • Directory.Get/SetAccessControl -> DirectoryInfo extensions (WindowsFileSystem, GVFSService)
  • Directory.CreateDirectory(path, security) -> DirectorySecurity.CreateDirectory(path)
  • Remove HttpRequestor machine.config lock and ServicePointManager usage
  • Remove UseDefaultCredentials from HttpClientHandler
  • Remove all .NET Framework assembly references (System.Web, System.Net.Http, etc.)

Scripts and installer:

  • Update output paths from net471 to net10.0-windows10.0.17763.0\win-x64
  • Remove ProjFS native DLL bundling from layout.bat (OS feature now)
  • Update installer MinVersion to 10.0.17763

Test fixes:

  • Add missing IVirtualizationInstance members to MockVirtualizationInstance
  • Remove stale GVFS.Service.UI project reference from UnitTests

All 803 unit tests pass (792 passed, 11 pre-existing skips).

Assisted-by: Claude Opus 4.6

@tyrielv tyrielv force-pushed the tyrielv/net10-tfm-retarget branch 7 times, most recently from 5efd7d7 to b58e509 Compare April 20, 2026 18:45
Phase 3 of the .NET 10 migration: TFM retarget, API migrations, and
build/CI updates consolidated into a single PR.

Foundation:
- Pin .NET 10 SDK in global.json (10.0.100 with latestFeature rollback)
- Centralize TargetFramework in Directory.Build.props
- Bump default dev version to 0.3.0.1 (official builds use 2.0.x.x)
- Update MSBuild SDK versions (Traversal 4.1.0, NoTargets 3.7.0)
- Update CI to .NET 10 SDK and windows-2025 runner

Package updates:
- Microsoft.Data.Sqlite 2.2.4 -> 9.0.4
- Microsoft.Build.* 16.0.461 -> 17.12.6
- Microsoft.Windows.ProjFS 1.1.19156.1 -> 2.1.0
- System.ServiceProcess.ServiceController 4.5.0 -> 9.0.4
- Add System.Diagnostics.EventLog, System.Management, System.IO.Pipes.AccessControl
- Remove GVFS.ProjFS package (ProjFS is now a Windows OS feature)
- Replace CommandLineParser and Newtonsoft.Json stale references

API migrations:
- HttpUtility.UrlEncode -> WebUtility.UrlEncode (OrgInfoApiClient)
- Assembly.Location -> Environment.ProcessPath (ProcessHelper, HooksInstaller)
- NamedPipeServerStream ctor -> NamedPipeServerStreamAcl.Create (WindowsPlatform)
- Directory.Get/SetAccessControl -> DirectoryInfo extensions (WindowsFileSystem, GVFSService)
- Directory.CreateDirectory(path, security) -> DirectorySecurity.CreateDirectory(path)
- Remove HttpRequestor machine.config lock and ServicePointManager usage
- Remove UseDefaultCredentials from HttpClientHandler
- Remove all .NET Framework assembly references (System.Web, System.Net.Http, etc.)

Scripts and installer:
- Update output paths from net471 to net10.0-windows10.0.17763.0\win-x64
- Remove ProjFS native DLL bundling from layout.bat (OS feature now)
- Update installer MinVersion to 10.0.17763

Test fixes:
- Add missing IVirtualizationInstance members to MockVirtualizationInstance
- Remove stale GVFS.Service.UI project reference from UnitTests

All 803 unit tests pass (792 passed, 11 pre-existing skips).

Assisted-by: Claude Opus 4.6
Signed-off-by: Tyrie Vella <tyrielv@gmail.com>
@tyrielv tyrielv force-pushed the tyrielv/net10-tfm-retarget branch 13 times, most recently from 6984f48 to b7a0793 Compare April 22, 2026 16:41
NativeAOT compiles managed projects to native binaries, eliminating
the .NET runtime dependency. This fixes CI functional tests which run
on machines without .NET 10 installed.

Changes:
- Add SelfContained=true and PublishAot=true to Directory.Build.props
- Add OptimizationPreference=Speed for performance-critical system component
- Opt out test projects from AOT (NUnit uses reflection for discovery)
- Opt out GVFS.MSBuild (netstandard2.0 build task)
- Switch Build.bat from 'dotnet build' to 'dotnet publish' for managed projects
- Update all script output paths to include publish\ subdirectory
- Pin global.json to SDK 10.0.202 with rollForward=disable

Output: ~20 MB native GVFS.exe, 36.7 MB installer (vs 107 MB self-contained)

Assisted-by: Claude Opus 4.6
Signed-off-by: Tyrie Vella <tyrielv@gmail.com>
@tyrielv tyrielv force-pushed the tyrielv/net10-tfm-retarget branch 8 times, most recently from c272226 to 69c8913 Compare April 23, 2026 19:01
tyrielv added 4 commits April 24, 2026 08:45
Before: Functional tests hung indefinitely in CI with no output, making it
impossible to diagnose failures. The gvfs process calls had no timeout and
stdout/stderr were not streamed to the CI log.

Changes:
- Add [CI-DEBUG] logging to CloneAndMount and gvfs process invocations
- Add 5-minute timeout per gvfs process invocation in GVFSProcess.CallGVFS
- Redirect and stream stderr via BeginErrorReadLine for real-time CI output
- Add timeout-minutes: 60 to functional-tests.yaml test step
- Add --workers=1 to CI test runner for sequential execution

Result: Tests no longer hang indefinitely. CI logs show real-time gvfs
output for diagnosis. 48/56 tests passed in first run with output, revealing
6 specific failures to investigate (previously all 56 timed out silently).

Assisted-by: Claude Opus 4.6
Signed-off-by: Tyrie Vella <tyrielv@gmail.com>
Before: GVFS.Mount crashed with ArgumentNullException in
OnPlaceholderFileCreated/OnPlaceholderFolderCreated/OnPlaceholderFileHydrated
when ProjFS passed null for triggeringProcessImageFileName. This caused 5 of
6 CI test failures (4 Native_ProjFS tests + ResetHardDirectoryWithOneFileWrite).

Root cause: The new pure-C# ProjFS managed API (Microsoft.Windows.ProjFS 2.1.0)
uses Marshal.PtrToStringUni(pData->TriggeringProcessImageFileName) which returns
null when the native pointer is IntPtr.Zero (process ID 0, kernel operations).
The old C++/CLI wrapper explicitly checked for NULL and returned String.Empty:
  (callbackData->TriggeringProcessImageFileName != NULL)
      ? gcnew String(...) : String::Empty

ConcurrentDictionary.AddOrUpdate does not accept null keys, so the null
propagated up and crashed the mount process.

Fix: Null-coalesce to string.Empty in all three AddOrUpdate call sites,
matching the old C++/CLI behavior. This is defense-in-depth; the upstream
fix belongs in Microsoft.Windows.ProjFS (tracked but not yet filed).

Result: All 5 mount-crash test failures resolved. Slice 1 (which had the
same crash pattern) now passes 4/4 in CI.

Assisted-by: Claude Opus 4.6
Signed-off-by: Tyrie Vella <tyrielv@gmail.com>
Before: TruncatedObjectRedownloaded test failed 4/4 in CI. In the previous
CI run, file content had null bytes; in the latest run, the CorruptObjects
count assertion failed (expected initialCount+1, got initialCount).

Root cause: .NET 10's DeflateStream silently returns partial data on truncated
zlib input instead of throwing InvalidDataException (behavioral change from
.NET Framework 4.7.1). Verified with a standalone test:
  - .NET 4.7.1: DeflateStream throws InvalidDataException on truncated zlib
  - .NET 10: DeflateStream returns 30 of 45 expected bytes, no exception

In GitRepo.GetLooseBlobStateAtPath, the code relied on InvalidDataException
to detect corrupt objects and move them to the CorruptObjects folder. Without
the exception, the truncated object was treated as valid (LooseBlobState.Exists)
and partial/corrupt content was served to the caller.

Fix: Wrap the DeflateStream in a CountingStream that tracks bytes read. After
writeAction completes, compare actual bytes read to the size declared in the
git object header. If fewer bytes were read, mark the object as corrupt.
CountingStream fully delegates all operations to the inner stream, only adding
byte counting on Read/ReadByte.

Result: TruncatedObjectRedownloaded (slice 1) now passes 4/4 in CI.

Assisted-by: Claude Opus 4.6
Signed-off-by: Tyrie Vella <tyrielv@gmail.com>
Documentation for picking up the .NET 10 NativeAOT migration work from a
clean slate. Includes:

- docs/net10-migration-status.md: Current CI results, remaining failures
  with analysis, .NET 10 behavioral changes discovered, build commands,
  deferred items
- docs/miniksa-reference.md: What was applied from miniksa's prototype
  branch, what wasn't applied yet, and what original work we did beyond
  his branch

Assisted-by: Claude Opus 4.6
Signed-off-by: Tyrie Vella <tyrielv@gmail.com>
@tyrielv tyrielv force-pushed the tyrielv/net10-tfm-retarget branch from 69c8913 to 380033d Compare April 24, 2026 15:48
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.

1 participant